BZOJ4487 JSOI2015染色问题(组合数学+容斥原理)

  逐个去除限制。第四个限制显然可以容斥,即染恰好c种颜色的方案数=染至多c种颜色的方案数-染至多c-1种颜色的方案数+染至多c-2种颜色的方案数……

  然后是限制二。同样可以容斥,即恰好选n行的方案数=至多选n行的方案数-至多选n-1行的方案数+至多选n-2行的方案数……

  限制三同理。即容斥套容斥套容斥。复杂度O(nmc)。

  注意到容斥式子和二项式定理有千丝万缕的联系,用二项式定理去掉一维变成O(nclogm)。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
#define N 410
#define P 1000000007
int n,m,c,ans,C[N][N];
void inc(int &x,int y){x+=y;if (x>=P) x-=P;}
int ksm(int a,int k)
{
    int s=1;
    for (;k;k>>=1,a=1ll*a*a%P) if (k&1) s=1ll*s*a%P;
    return s;
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("bzoj4487.in","r",stdin);
    freopen("bzoj4487.out","w",stdout);
    const char LL[]="%I64d\n";
#else
    const char LL[]="%lld\n";
#endif
    n=read(),m=read(),c=read();
    C[0][0]=1;
    for (int i=1;i<=400;i++)    
    {
        C[i][0]=C[i][i]=1;
        for (int j=1;j<i;j++)
        C[i][j]=(C[i-1][j]+C[i-1][j-1])%P;
    }
    for (int i=c;i>=0;i--)
        for (int j=n;j>=1;j--)
        if ((c-i+n-j+m&1)^(m&1)) inc(ans,P-1ll*C[c][i]*C[n][j]%P*ksm(ksm(i+1,j)-1,m)%P);
        else inc(ans,1ll*C[c][i]*C[n][j]%P*ksm(ksm(i+1,j)-1,m)%P);
    cout<<ans;
    return 0;
}

 

posted @ 2018-10-31 14:35  Gloid  阅读(304)  评论(0编辑  收藏  举报