【題解】AT3954 [AGC023C] Painting Machines

AT3954 [AGC023C] Painting Machines

\(\text{Solution:}\)

首先可以考慮對每個數拆貢獻,一個數如果有貢獻顯然是它自己有貢獻或者排在它後面的數有貢獻。

這個東西看起來就不好做。所以直接容斥掉,變成求它有多少情況不貢獻。

此時當且僅當它後面的數和它自己全部沒有貢獻。

那麼從這一步開始,我們發現,這個數具體是多少已經不重要了,我們現在只需要知道,有多少長度爲 \(i\) 的後綴,其全部沒有貢獻。

現在需要明確一下:先考慮轉化爲 有多少長度爲 \(i\) 的排列可以覆蓋全部格子。 接下來我們發現,後面的 \(n-i-1\) 是可以隨便排列的,而前面這 \(i\) 個也是可以隨便排的,現在就剩下如何確定有多少種方案有 \(i\) 個可以覆蓋所有格子。

剩下就是我沒有想到的地方了)

考慮設集合爲 \(S\) (由於之前把隨便排給去掉了,所以此時是沒有順序的,後面要乘一個 \(i!\times (n-i-1)!\)

那麼不妨認定它是有順序的,它需要滿足下列條件:

  • \(1\in S,n-1\in S\)
  • \(\forall i,S_{i+1}-S_i\leq 1\)

第一步是因爲 \(1,n\) 只能被這樣覆蓋,第二步是因爲,如果不滿足,那麼 \(S_i+2\) 就無法覆蓋。

考慮怎麼求 \(S\) 的個數。我們發現,現在可以從元素位置差的角度來考慮。

首先要發現一個性質:\(\left(\sum S_i-S_{i-1}\right)=n\)

那麼考慮這個間隙應當滿足什麼條件:設 \(|S|=t,\) 則我們需要空出 \(n-t-1\) 個位置,而一共有 \(t\) 個元素,所以一共有 \(t-1\) 個空隙。

那麼不妨表示爲方程,則有:

\[\sum _{i=1}^{t-1} x_i=n-t-1,x_i\in\{0,1\} \]

考慮生成函數,將每個 \(x\) 寫成 GF 形式,所求即爲:

\[F=\prod_{i=1}^{t-1} (1+x) \\ Ans=[x^n]F(x) \]

考慮其 \(n\) 次項的係數,容易發現這個是楊輝三角。

那麼就有:

\[Ans=\binom{t-1}{n-t-1} \]

於是整理上述過程,設 \(f_i=\binom{t-1}{n-t-1},\)

\[Ans=\sum f_i\times i!\times (n-i-1)! \]

組合意義就是:找到大小爲 \(i\) 的合法集合方案數,集合內部隨便排,外部隨便排。注意其不能交叉,是因爲這裏強制了 \(S\) 排在前面。

預處理階乘就可以線性了。最後答案是 \(n\times (n-1)!-Ans.\)

止步在了容斥完的地方……思維跑到分兩端組合了,後面一段的階乘想到了,問題在於沒有想到前面一段可以乘階乘去掉順序之後有一個差 \(\leq 1\) 的限制,利用限制化爲方程解數求解的方法。

#include <bits/stdc++.h>
using namespace std;
typedef double db;
//#define int long long
#define fi first
#define se second
#define mk make_pair
#define pb emplace_back
#define poly vector<int>
#define Bt(a) bitset<a>
#define bc __builtin_popcount
#define pc putchar
#define ci const int&
const int mod = 1e9 + 7;
const db eps = 1e-10;
const int inf = (1 << 30);
inline int Max(ci x, ci y) {return x > y ? x : y;}
inline int Min(ci x, ci y) {return x < y ? x : y;}
inline db Max(db x, db y) {return x - y > eps ? x : y;}
inline db Min(db x, db y) {return x - y < eps ? x : y;}
inline int Add(ci x, ci y, ci M = mod) {return (x + y) % M;}
inline int Mul(ci x, ci y, ci M = mod) {return 1ll * x * y % M;}
inline int Dec(ci x, ci y, ci M = mod) {return (x - y + M) % M;}
typedef pair<int, int> pii;
inline int Abs(int x) {return x < 0 ? -x : x;}
//char buf[1<<21],*p1=buf,*p2=buf;
//#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char Obuf[105000],*O=Obuf;//Siz shoule be the size of Out File
int pst[30],ptop;
inline void Fprint(){fwrite(Obuf,1,O-Obuf,stdout);}
inline void Fwrite(int x){
  if(x==0){*O++='0';return;}
  if(x<0)*O++='-',x=-x;ptop=0;
  while(x)pst[++ptop]=x%10,x/=10;
  while(ptop)*O++=pst[ptop--]+'0';
  if(O-Obuf>100000)Fprint(),O=Obuf;
}
inline int read() {
    int s = 0, w = 1;
    char ch = getchar();
    while (!isdigit(ch)) {if (ch == '-') w = -1;ch = getchar();}
    while (isdigit(ch)) {s = s * 10 + ch - '0';ch = getchar();}
    return s * w;
}
inline void write(int x) {
    if (x < 0)putchar('-'), x = -x;
    if (x > 9)write(x / 10);
	pc(x % 10 + '0');
}
inline int qpow(int x, int y) {
    int res = 1;
    while (y) {if (y & 1)res = Mul(res, x);x = Mul(x, x);y >>= 1;}
    return res;
}
inline void cadd(int &x, int y) {x += y;}
inline void cmul(int &x, int y) {x *= y;}
inline void cmax(int &x, int y) {x = Max(x, y);}
inline void cmin(int &x, int y) {x = Min(x, y);}
const int N=2e6+10;
namespace Refined_heart{
	int n,ans,fac[N],inv[N];
	inline int C(int x,int y){
		if(y>x)return 0;
		return Mul(fac[x],Mul(inv[y],inv[x-y]));
	}
	void solve(){
		n=read();
		fac[0]=1;
		for(int i=1;i<=n;++i)fac[i]=Mul(fac[i-1],i);
		ans=Mul(fac[n-1],n);
		inv[n]=qpow(fac[n],mod-2);
		for(int i=n;i>=1;--i)inv[i-1]=Mul(inv[i],i);
		for(int i=1;i<=n;++i)ans=Dec(ans,Mul(fac[i],Mul(fac[n-i-1],C(i-1,n-i-1))));
		write(ans);
	}
}
int main(){
	Refined_heart::solve();
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章