Description
Solution
- 简单的计数,但是我的考虑方向并不正确,设的状态也不好做,导致正解其实并不难,但是我在考场上没有做出来。
- 既然已经给定了顺序,那么一段满足条件一定是前几个字符完全一样,后面再区分开来。
- 如果我们按照从后往前的顺序做,就很好转移,有点类似区间DP。
- 设表示到的后i位已经确定并且能区分开来,第i位最大的字符为c
- 枚举一个,让r+1~r’的第i位都为字符c’,转移到
- 要满足c<c’,所以用一个前缀和优化一下就好了。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define maxn 55
#define maxl 22
#define ll long long
#define mo 990804011
using namespace std;
int n,i,j,k,L,l,r,len[maxn];
char ch;
int s[maxn][maxl];
ll f[maxl][maxn][maxn][27];
int main(){
freopen("b.in","r",stdin);
freopen("b.out","w",stdout);
scanf("%d",&n);
for(i=1;i<=n;i++){
for(ch=getchar();(ch<'a'||ch>'z')&&ch!='?';ch=getchar());
for(;(ch>='a'&&ch<='z')||ch=='?';ch=getchar()) {
++len[i];
if (ch=='?') s[i][len[i]]=-1; else
s[i][len[i]]=ch-'a'+1;
}
L=max(L,len[i]);
}
for(i=1;i<=n;i++) f[L+1][i][i][26]=1;
for(k=L;k>=1;k--){
for(l=1;l<=n;l++) if (s[l][k]==0) f[k][l][l][0]=1;
for(l=1;l<=n;l++) for(r=l;r<=n;r++) {
for(j=1;j<=26;j++){
f[k][l][r][j]=f[k][l][r][j-1];
for(i=r;i>l&&(s[i][k]==-1||s[i][k]==j);i--)
f[k][l][r][j]+=f[k][l][i-1][j-1]*f[k+1][i][r][26]%mo;
if (i==l&&(s[i][k]==-1||s[i][k]==j))
f[k][l][r][j]+=f[k+1][l][r][26];
f[k][l][r][j]%=mo;
}
}
}
printf("%lld",f[1][1][n][26]);
}