ZROI2018提高day6t2
分析
将所有字母分别转化为1~26,之后将字符串的空位补全为0,?设为-1,我们设dp[p][c][le][ri]表示考虑le到ri个字符串且从第p位开始考虑,这一位最小填c的方案数,具体转移见代码。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
const long long mod = 990804011;
#define add(x,y) x=(x+y)%mod
long long dp[25][30][60][60];
int len[60],n,m,a[60][25];
char s[60][25];
inline long long getdp(int p,int c,int le,int ri){
if(c>26)return 0;
if(p>m)return le==ri;
if(dp[p][c][le][ri]!=-1)return dp[p][c][le][ri];
dp[p][c][le][ri]=getdp(p,c+1,le,ri);
for(int i=le;i<=ri;i++){
if(!c&&a[i][p]==-1)break;
if(a[i][p]>=0&&a[i][p]!=c)break;
long long t=getdp(p+1,0,le,i);
if(i!=ri)t=t*getdp(p,c+1,i+1,ri)%mod;
add(dp[p][c][le][ri],t);
}
return dp[p][c][le][ri];
}
int main(){
int i,j,k;
scanf("%d",&n);
memset(dp,-1,sizeof(dp));
for(i=1;i<=n;i++){
scanf("%s",s[i]);
len[i]=strlen(s[i]);
m=max(m,len[i]);
}
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
if(j>len[i])a[i][j]=0;
else if(s[i][j-1]=='?')a[i][j]=-1;
else a[i][j]=s[i][j-1]-'a'+1;
printf("%lld\n",getdp(1,0,1,n));
return 0;
}