- 题意:给一个字符串s,有两种操作,对于1<=p<|s|,1.s[p]++, s[p+1]–2.s[p]–,s[p+1]++。如果进行操作后 s[p]或者s[p+1]不为小写字母,则操作非法。可以进行无数次这样的操作,通过这两个操作可以变化出多少种不同的字符串。
- 思路:可以发现无论进行多少次这样的操作,字符串s每一位的ascii码值之和都不会改变,并且对于任意两个长度相同并且每一位的ascii码值之和的字符串都可以通过有限次的这两种操作转换。所以这个问题等价于长度为n,每一位的ascii值之和为sum的字符串有多少种。到这里就很容易想到用dp来解决这个问题。定义dp[i][j]表示长度为i,ascii码之和为j的字符串有多少种,可以得出状态转移方程为dp[i+1][j]=∑′z′k=′a′,j−k>0dp[i][j−k]。
- 小小的感想:其实如果这道题直接让求长度为n,每一位的ascii码值之和相加为sum的字符串有多少种,这道题就是一道很水的题目了,然而换了一种方式来提出这个问题就对思维的要求高了不少,所以遇到问题的时候,根据题目中已知的条件,找找能不能得到一些有用的结论,然后尝试是否可以通过这些结论将题目转化为一个更简单的模型,是一个很有效的思维方法。
- 代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100 + 5;
const int mod = 1000000000 + 7;
int dp[100][2600];
char str[maxn];
void initial()
{
for(int i = 0; i < 26; i++) {
dp[0][i] = 1;
}
for(int i = 1; i < 100; i++) {
for(int j = 0; j < 2600; j++) {
for(int k = 0; k < 26; k++) {
if(j - k >= 0) {
dp[i][j] = (dp[i][j] + dp[i-1][j-k]) % mod;
}
}
}
}
}
int main()
{
initial();
int t;
scanf("%d", &t);
while(t--) {
scanf("%s", &str);
int len = strlen(str);
int sum = 0;
for(int i = 0; i < len; i++) {
sum += str[i] - 'a';
}
printf("%d\n", dp[len-1][sum] - 1);
}
return 0;
}