1. 程式人生 > >bzoj 4487: [Jsoi2015]染色問題

bzoj 4487: [Jsoi2015]染色問題

簡述題意:

演算法:組合數+容斥(不好推)

難度:NOIP+ 

題解:

首先,你可以用O(nmc)的時間複雜度水過這道題!

公式為:

我是不會告訴你這公式很好推的,反正我自己推不出來,看完題解,大概可能明白了吧

如果你不甘心於水過這道題,你可以對上面的公式進行優化,優化成時間複雜度為O(n*m*logc)

推導過程如下:

①<=>②(只是調換了\sum的順序...)

又因為

所以,綜合②③式可得, 

因此,利用 ④式,就可以在O(nmlogc)的時間複雜度內,解決這道題!

程式碼如下:

#include <bits/stdc++.h>
#define ll long long
#define N 405
using namespace std;
const ll p=1000000007;
ll inv[N],jc[N];
void ny()
{
	inv[0]=1;
	inv[1]=1;
	for(int i = 2;i <= 400;i++)
	{
		inv[i]=(p-p/i)*inv[p%i]%p;
	}
	jc[1]=1;
	for(int i = 2;i <= 400;i++)
	{
		jc[i]=((jc[i-1]%p)*i)%p;
	}
	for(int i = 2;i <= 400;i++)
	{
		inv[i]=(inv[i-1]*inv[i])%p;
	}
}
ll powermod(ll x,ll y)
{
	ll ret=1;
	while(y)
	{
		if(y%2)
		{
			ret=ret*x%p;
		}
		y=y/2;
		x=x*x%p;
	}
	return ret;
}
ll C(int n, int m)
{
    return jc[n]*inv[m]%p*inv[n-m]%p;
}
ll ans;
int main()
{
	int n,m,kk;
	scanf("%d%d%d",&n,&m,&kk);
	ny();
	for (int i = 0;i <= n;i++)
	{
		for (int k = 0;k <= kk;k++)
         {
             ll qwq=C(n,i)*C(kk,k)%p;
             ll orz=powermod((1-powermod(k+1,i)+p)%p,m);
             qwq=qwq*orz%p;
             if ((n+m+kk-i-k)%2) qwq=-qwq;
             ans=(ans+qwq)%p;
         }
	}     
    printf("%lld\n",(ans+p)%p);
	return 0 ;
}