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;
}
posted @ 2018-10-16 15:46  水题收割者  阅读(155)  评论(0编辑  收藏  举报