字符串统计
有n 个不同的字符串都只包含小写字母,它们都由字典序排序后,并且满足
s1<s2<s3<...<sn。然而,有些字符看不见了,我们用?代替,那么有多少种可
能满足给定的条件?
输入:
第一行包含一个n 表示字符串个数
接下来n 行顺序从s1 到s2 到...到sn,n 个字符串只由小写字母和问号组成。
对于20%的数据n<=2,每个字符串长度不超过2
对于100%的数据n<=50,每个字符串长度不超过20
因为区间外的字符串顺序互补影响,所以考虑区间dp
dp[l][r][p][c]表示区间l,r;每个字符串考虑到p位置,可以填>=c的字符,直接转移。
因为前面的位决定以后就不需要再考虑前面的了,只需知道现在可以填哪些字符
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 #define mod 1000000007 7 typedef long long LL; 8 9 char ch[100][100]; 10 int n; 11 const char mn = char('a' - 1),mx = 'z'; 12 int dp[100][100][50][50]; 13 14 int DP(int l,int r,int p,int c){ 15 if ( c > mx ) return 0; 16 if ( p > 20 ) return l == r; 17 int &d = dp[l][r][p][c]; 18 if ( d != -1 ) return d; 19 d = 0; 20 d = DP(l,r,p,c + 1); 21 for (int i = l ; i <= r ; i++){ 22 if ( ch[i][p] != '?' && ch[i][p] != c ) break; 23 if ( ch[i][p] == '?' && c == mn ) break; 24 int v = DP(l,i,p + 1,mn); 25 if ( i < r ) v = ((LL)v * (LL)DP(i + 1,r,p,c + 1)) % mod; 26 d = (d + v) % mod; 27 } 28 return d; 29 } 30 int main(){ 31 freopen("a.in","r",stdin); 32 freopen("a.out","w",stdout); 33 scanf("%d",&n); 34 memset(dp,-1,sizeof(dp)); 35 for (int i = 1 ; i <= n ; i++){ 36 scanf("%s",ch[i] + 1); 37 int l = strlen(ch[i] + 1); 38 for (int j = l + 1 ; j <= 20 ; j++){ 39 ch[i][j] = mn; 40 } 41 } 42 printf("%d ",DP(1,n,1,mn)); 43 }
多总结dp的方法,从菜鸡慢慢变强!