Codeforces 156c Cipher

  • 题意:给一个字符串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]=zk=ajk>0dp[i][jk]
  • 小小的感想:其实如果这道题直接让求长度为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;
}

你可能感兴趣的:(codeforces,乱搞题)