SPOJ:http://www.spoj.com/problems/ACODE/
题目翻译
A和B希望给对方发送聊天信息并且加密数据传输,他们讨论后希望这样加密数据:
A:“让我们用一种十分简单的加密方式:令字符’A’的编码为1,’B’的编码为2,以此类推,直到’Z’的编码是26。”
B:“mdzz,假设我发给你单词’BEAN’,加密后为25114,但是解密的可能结果有很多种!”
A:“你还是too young! 你觉得有哪些解呢?’BEAAD’? ‘YAAD’? ‘YAN’? ‘YKD’? 还是 ‘BEKD’? 都不是正确的单词吧?所以最后你还是会觉得我发给你的结果是’BEAN’,对吧?”
B:“是啦是啦,我的例子不好啦,但是如果你发了一条长达5000的字符串,将会有一大坨的解密方法啊?至少会有2种方法可行吧?”
A:“多少种呢?”
B:“让ACM选手解决吧!”
输入
有多组数据,每组数据一行一个数字串,长度不超过5000,而且是某一个字符串的加密结果,数字间没有空格。一行输入:‘0’表示输入结束。
输出
对于每组数据,输出一行一个正整数,表示可能的解密方案的数量,结果保证在long long内。
样例输入
25114
1111111111
3333333333
0
样例输出
6
89
1
题解
本题可能会有一些小坑,比如01不能被解密为’A’,单个数字0没有对应字符,所以处理的时候要特别注意一下。
本题显然是个动态规划题,因为某位看成一位数字还是和前面一位数字合在一起看成二位数字,都不影响后面的状态。
令dp[i]
表示到第i位的可能解的个数。显然有如下的方程:
dp[i]=dp[i-1](*1)+dp[i-2](*2)
(*1) digits[i]不为0,转移表示第i位单独解析为一个字母,当然没有对应0的字母。
(*2) 合并digits[i]和digits[i-1]后不超过26,digits[i-1]不为0,因为01不表示A,超过26显然不对应字母。
代码
#include <cstdio>
#include <cstring>
#define FOR(i,j,k) for(i=j;i<=k;++i)
const int N = 10005;
char digits[N];
long long dp[N];
int main() {
int i, len;
while (scanf("%s", digits + 1) == 1) {
len = strlen(digits + 1);
if (len == 1 && digits[1] == '0') break;
FOR(i,1,len) digits[i] -= '0';
dp[0] = dp[1] = 1;
FOR(i,2,len) {
if (digits[i] == 0) dp[i] = 0;
else dp[i] = dp[i - 1];
if (digits[i - 1] == 2 && digits[i] > 6) continue;
if (digits[i - 1] > 2 || digits[i - 1] == 0) continue; // 01 is not A.
dp[i] += dp[i - 2];
}
printf("%lld\n", dp[len]);
}
return 0;
}