容斥原理两则

  • 这两个套路都是把恰好....转化成了至少.....,最后根据容斥原理递推出恰好的值

[SDOI2009]Bill的挑战

  • f[i]表示至少与i个字符串匹配的方案数
  • ans[i]表示只与i个字符串匹配的方案数

 Code

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
const int mod=1000003;
const int N=100;
int b[N],f[N],ans[N],c[N][N],T,n,k,cnt,len;
char a[N][N];
int get(int S){
    int num=0,now=1;cnt=0;
    while(S){
        if(S&1){
            num++;
            b[++cnt]=now;
        }
        S>>=1;
        now++;
    }return num;
}
int work(){
    char tmp[N];int ans=1;
    rep(i,1,len)tmp[i]='?';
    rep(i,1,cnt){
        rep(j,1,len){
            if(a[b[i]][j]=='?')continue;
            if(tmp[j]!='?'&&tmp[j]!=a[b[i]][j])return 0;
            tmp[j]=a[b[i]][j];
        }
    }
    rep(i,1,len)if(tmp[i]=='?')ans=26*ans%mod;
    return ans; 
}
void init(){
    memset(f,0,sizeof(f));
    memset(ans,0,sizeof(ans));
}
int main()
{
    scanf("%d",&T);
    c[0][0]=1;
    rep(i,1,50){
        c[i][0]=1;
        rep(j,1,50)
        c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
    }
    while(T--){
        init();
        scanf("%d%d",&n,&k);
        rep(i,1,n)scanf("%s",a[i]+1);
        len=strlen(a[1]+1);
        
        rep(S,1,(1<<n)-1){
            int num=get(S);
            f[num]=(f[num]+work())%mod;
        }
        per(i,n,k){
            ans[i]=f[i];
            rep(j,i+1,n){
                ans[i]=(ans[i]-1LL*c[j][i]*ans[j]%mod+mod)%mod;
            }
        }printf("%d\n",ans[k]);
    }
    return 0;
}

[HAOI2018]染色

  • f[i]表示至少有i种颜色出现了S次
  • ans[i]表示有i种颜色出现了S次

  • 暴力计算45pts
#include<bits/stdc++.h>
#define rep(i,a,b) 	for(register int i=(a);i<=(b);++i)
#define per(i,a,b) 	for(register int i=(a);i>=(b);--i)
#define C(n,m) 		1LL*fact[n]*ifact[n-m]%mod*ifact[m]%mod
#define inv(x) 		power(x,mod-2)
using namespace std;
const int mod=1004535809;
const int N=1e6+100;
int f[N],fact[N],ifact[N],ans[N],val[N],tot=0,n,m,s,lim;
int power(int a,int b)
{int ans=1;for(;b;b>>=1,a=1LL*a*a%mod)if(b&1)ans=1LL*ans*a%mod;return ans;}
int main()
{
    scanf("%d%d%d",&n,&m,&s);
    rep(i,0,m)scanf("%d",&val[i]);
    fact[0]=1;rep(i,1,N-100)fact[i]=1LL*i*fact[i-1]%mod; 
    rep(i,0,N-100)ifact[i]=inv(fact[i]);
    lim=min(m,n/s);
    rep(i,0,lim)f[i]=1LL*C(m,i)*fact[n]%mod*inv(power(fact[s],i))%mod*inv(fact[n-i*s])%mod*power(m-i,n-i*s)%mod;
    per(i,lim,0){
        ans[i]=f[i];
        rep(j,i+1,lim){
            ans[i]=(ans[i]-1LL*C(j,i)*ans[j]%mod+mod)%mod;
        }
    }
    rep(i,0,lim)tot=(tot+1LL*val[i]*ans[i]%mod)%mod;
    cout<<tot;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/strangeDDDF/article/details/88200573