Gym - 100548F Color 組合數+容斥
阿新 • • 發佈:2018-11-02
題意:給你N朵花,M種顏料(n,m<=1e9),要求給所有花染色,且相鄰的花不能用同樣的顏色,求出最後恰好用了k種
顏料的方案數(k<=1e5)
題解:當我們用至少k中染色的時候 f[k] = k*(k-1)^(n-1) 其中包括了 至少k-1中的,我們需要減去C(k,k-1)*f[k-1] ,但是很明顯我們多減了一次至少f[k-2]次的,舉個栗子:假設有1 2 3 4 5,我們先減去1 3 4 5 在減 2 3 4 5 所以其中多減了一次 3 4 5的 所以要再加上y一次f[k-2] 以此類推 ,這就是一個容斥,但是n,k,很大我們怎麼辦的,C(n,m+1)=C(n,m)*(n-m)/(m+1) 因此我們就需要求逆元了
注意乘法運算啊,每次乘,都要取模,否則就超1e9了 坑
#include<iostream> #include<cstdio> using namespace std; typedef long long ll; const int N=1e6+100; const ll mod=1000000007; ll C[N],inv[N],n,m,k; ll ksm(ll a,ll b) { ll ans=1; while(b) { if(b&1) ans=ans*a%mod; b>>=1; a=a*a%mod; } return ans; } void init() { for(int i=1;i<N;i++) inv[i]=ksm(i,mod-2); } void cal(ll x) { C[0]=1; for(int i=1;i<=k;i++) C[i]=((C[i-1]*(x-i+1)%mod)*inv[i]%mod)%mod; } int main() { init(); int T,nn=1; scanf("%d",&T); while(T--) { scanf("%lld%lld%lld",&n,&m,&k); cal(k); ll ans=k*ksm(k-1,n-1)%mod; for(ll i=2;i<=k-1;i++) { if((k-i)%2) ans=(ans-C[i]*(i*ksm(i-1,n-1)%mod)%mod)%mod; else ans=(ans+C[i]*(i*ksm(i-1,n-1)%mod)%mod)%mod; } cal(m); printf("Case #%d: %lld\n",nn++,(C[k]*ans%mod+mod)%mod); } return 0; }