题解 [SDOI2009]Bill的挑战
题目描述
给
n
n
n个字符串,每个字符串由a
~z
或者?
组成,其中?
可以匹配任意字符。
现在问有多少个串 T T T,满足能够恰好与 n n n个串中的 k k k个匹配。
n ≤ 20 , n \leq 20, n≤20,字符串长度 ≤ 50 \leq 50 ≤50。
具体做法
这是一道容斥题,当然一看数据范围也可以用状压 d p dp dp写。
考虑我们能够预处理出什么,数据这么小那么我们可以爆搜处理出 T T T至少匹配了 i i i个串的总数,记为 t o t i tot_i toti。
(暴力枚举选择情况,再来匹配)。
那么题目要求的恰好匹配 k k k个就可以用总的减去多选的。
设 a n s i ans_i ansi表示从 n n n个中恰好匹配 i i i个的方案,现在要求 a n s j , j < i ans_j,j < i ansj,j<i。
首先我们把 a n s j ans_j ansj加上 t o t j tot_j totj。那么现在多算了实际上一定能够匹配 i i i个串,但只选了 j j j个串来匹配的方案。
对于能够匹配 i i i个串的方案,我们若去掉任意 i − j i-j i−j个串,那么就能够成为一个非法的恰好只匹配 j j j个串的方案,从中去掉 i − j i-j i−j个串有 C i i − j C_{i}^{i-j} Cii−j个方案。
所以有 a n s j = t o t j − ∑ i = j + 1 n ( i i − j ) a n s i ans_j=tot_j-\sum_{i=j+1}^{n}(_i^{i-j})ans_i ansj=totj−∑i=j+1n(ii−j)ansi。
C o d e \mathcal{Code} Code
/*******************************
Author:galaxy yr
LANG:C++
Created Time:2019年10月27日 星期日 20时28分52秒
*******************************/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#define int long long
using namespace std;
const int maxn=55;
const int mod=1000003;
int n,k,len,stk[maxn],_top,num,tot,c[maxn][maxn],ans[maxn];
string a[maxn];
void dfs(int now,int chos)
{
if(now==n+1)
{
if(chos!=num) return;
long long res=1;
for(int i=1;i<=len;i++)
{
int ch=-1;
for(int j=1;j<=num;j++)
{
if(a[stk[j]][i]!='?')
{
if(ch==-1)
ch=a[stk[j]][i]-'a';
else if(ch!=a[stk[j]][i]-'a')
return;
}
}
if(ch==-1)
res=res*26LL%mod;
}
tot=(tot+res)%mod;
return;
}
if(chos<num)
{
stk[++_top]=now;
dfs(now+1,chos+1);
stk[_top--]=0;
}
if(n-now>=num-chos)
dfs(now+1,chos);
}
inline void init(int n=50)
{
for(int i=0;i<=n;i++)
c[i][i]=c[i][0]=1;
for(int i=2;i<=n;i++)
for(int j=1;j<i;j++)
c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
}
signed main()
{
//freopen("p2167.in","r",stdin);
//freopen("p2167.out","w",stdout);
ios::sync_with_stdio(false);
int T;
cin>>T;
init();
while(T--)
{
cin>>n>>k;
for(int i=1;i<=n;i++)
cin>>a[i],a[i]="$"+a[i];
len=a[1].size()-1;
for(int i=n;i>=k;i--)
{
tot=0,num=i; _top=0;
dfs(1,0);
long long res=0;
for(int j=i+1;j<=n;j++)
res=(res+1ll*c[j][i]*ans[j])%mod;
ans[i]=(tot-res+mod)%mod;
}
cout<<ans[k]<<endl;
}
return 0;
}