1. 程式人生 > >[HAOI2018]染色

[HAOI2018]染色

中一 組合數 ios 題解 return using -- etc base

題目描述

為了報答小 C 的蘋果, 小 G 打算送給熱愛美術的小 C 一塊畫布, 這塊畫布可 以抽象為一個長度為 N 的序列, 每個位置都可以被染成 M 種顏色中的某一種.

然而小 C 只關心序列的 N 個位置中出現次數恰好為 S 的顏色種數, 如果恰 好出現了 S 次的顏色有 K 種, 則小 C 會產生 Wk? 的愉悅度.

小 C 希望知道對於所有可能的染色方案, 他能獲得的愉悅度的和對 1004535809取模的結果是多少。

題解

碰到這種等於什麽什麽的題要考慮容斥。

既然是容斥,那麽先設cnt[i]表示至少有i種出現了s次的顏色的方案數。

這個可以直接算,先C(m,i)選顏色,然後每種顏色的s種看做一個整體,其余的n-i*s看做一個整體,算一下排列n!/((s!)i

*(n-s*i)!)先求一下排列數。

然後剩下的n-s*i個位置可以隨便填m-i種顏色,乘上(m-i)n-s*i就可以了。

然後繼續容斥。

ans[k]=∑(-1)i-kC(i,k)*cnt[i]

然後我們把組合數拆開,用FFT優化就好了。

不過我們發現它的卷積是個反著的,把其中一個數組reverse一下就好了。

代碼

#include<iostream>
#include<cstdio>
#define N 10000009
#define M 100009
using namespace std;
typedef long long ll;
const int mod=1004535809
; const int Gi=334845270; const int G=3; ll n,m,jie[N],ni[N],a[M<<2],val[M<<2],w[M],s,b[M<<2],l,L,rev[M<<2],ans; inline int rd(){ ll x=0;char c=getchar();bool f=0; while(!isdigit(c)){if(c==-)f=1;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f?-x:x; } inline ll power(ll x,ll y){ ll ans=1; while(y){if(y&1)ans=ans*x%mod;x=x*x%mod;y>>=1;} return ans; } inline ll ny(ll x){return power(x,mod-2);} inline ll C(int n,int m){return jie[n]*ni[m]%mod*ni[n-m]%mod;} inline void NTT(ll *a,int tag){ for(int i=1;i<l;++i)if(i>rev[i])swap(a[i],a[rev[i]]); for(int i=1;i<l;i<<=1){ ll wn=power(tag==1?G:Gi,(mod-1)/(i<<1)); for(int j=0;j<l;j+=(i<<1)){ ll w=1; for(int k=0;k<i;++k,w=w*wn%mod){ ll x=a[k+j],y=a[i+j+k]*w%mod; a[k+j]=(x+y)%mod;a[i+j+k]=(x-y+mod)%mod; } } } } int main(){ n=rd();m=rd();s=rd();int num=max(n,m); for(int i=0;i<=m;++i)w[i]=rd(); jie[0]=1; for(int i=1;i<=num;++i)jie[i]=jie[i-1]*i%mod;ni[num]=power(jie[num],mod-2); for(int i=num-1;i>=0;--i)ni[i]=ni[i+1]*(i+1)%mod; for(int i=0;i<=m;++i)if(n-i*s>=0){ val[i]=C(m,i)*jie[n]%mod*power(ni[s],i)%mod*ni[n-s*i]%mod*power(m-i,n-s*i)%mod; } for(int i=0;i<=m;++i){ a[m-i]=jie[i]*val[i]; b[i]=ni[i];if(i&1)b[i]=(-b[i]+mod)%mod; } l=1;L=0; while(l<=(m<<1))l<<=1,L++; for(int i=1;i<l;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1)); NTT(a,1);NTT(b,1); for(int i=0;i<l;++i)a[i]=a[i]*b[i]%mod; NTT(a,-1);int nn=power(l,mod-2); for(int i=0;i<l;++i)a[i]=a[i]*nn%mod; for(int i=0;i<=m;++i)(ans+=a[m-i]*w[i]%mod*ni[i]%mod)%=mod; cout<<ans; return 0; }

[HAOI2018]染色