bzoj4487: [Jsoi2015]染色问题

隔壁Rose爷爷:这个随便容斥一下写完就过了

我:。。。

我的做法很菜鸡,首先颜色给它变成最多用多少,然后再容斥

然后搞二维你设f[i][j]为i行为0j列为0的数量,再考虑容斥会发现一个很像二维二项式反演的东西。。。

我不知道能不能直接用啊(捂脸,那就设了个类似前缀和带上组合数的东西,先反演出这个,再反演出f

其实三个容斥可以套在一起直接算。。。。

成功卡常。。

有个更强的推导 这个二项式定理还是用得很妙的 我的博客没法看了

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const int maxn=4e2+10;
const LL mod=1e9+7;

LL C[maxn][maxn];
void yu()
{
    C[0][0]=1;
    for(int i=1;i<maxn;i++)
    {
        C[i][0]=1;
        for(int j=1;j<=i;j++)
        {
            C[i][j]=C[i-1][j]+C[i-1][j-1];
            if(C[i][j]>=mod)C[i][j]-=mod;
        }
    }
}
LL g[maxn][maxn],h[maxn],mi[maxn*maxn];
int main()
{
    int n,m,cc;
    scanf("%d%d%d",&n,&m,&cc); yu();
    int cop=1;LL ans=0;
    for(int c=cc;c>=0;c--)
    {
        mi[0]=1;for(int i=1;i<=n*m;i++)mi[i]=mi[i-1]*(c+1)%mod;
        
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
                g[i][j]=C[n][i]*C[m][j]%mod*mi[(n-i)*(m-j)]%mod;
        for(int i=0;i<=n;i++)g[i][m]=C[n][i];
        for(int j=0;j<=m;j++)g[n][j]=C[m][j];
                
        for(int j=0;j<=m;j++)
        {
            int op=1; h[j]=0;
            for(int u=0;u<=n;u++)
            {
                if(op==1)h[j]+=g[u][j];
                else h[j]-=g[u][j];
                op=-op;
            }
            h[j]%=mod;
            if(h[j]<0)h[j]+=mod;
        }
            
        LL f=0; int op=1;
        for(int v=0;v<=m;v++)
        {
            if(op==1)f+=h[v];
            else f-=h[v];
            op=-op;
        }
        f%=mod;
        if(f<0)f+=mod;
        
        if(cop==1)ans+=C[cc][c]*f%mod;
        else ans-=C[cc][c]*f%mod;
        cop=-cop;
    }
    ans%=mod;
    if(ans<0)ans+=mod;
    printf("%lld
",ans);
    
    return 0;
}
原文地址:https://www.cnblogs.com/AKCqhzdy/p/10614189.html