- 这两个套路都是把恰好....转化成了至少.....,最后根据容斥原理递推出恰好的值
[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;
}