百度清一色的数学方法, 惟一的动态规划还是有问题的
数学方法无法参悟,于是参考了动态规划方法的建表,自己又写了一遍
首先是建表,表格大小7*27,其中第一行为了方便是闲置的
行代表字符串长度,列代表字符串起始字母;
第一行(i=1)第一列(j=0)代表以a开头长度为1的字符串个数,显然是1;
第一行均为长度为1的字符串,个数均为1;
第一行最后一列记录这一行的总数,这里是26;
第二行第一列代表以a开头长度为2的字符串个数,显然是a[1][26]-a[1][0],以b开头长度为2的字符串个数是a[1][26]-a[1][0]-a[1][1],以此类推;
第二行开始需要注意以z开头没有长度超过1的字符串,y开头没有长度超过2的字符串...等等;
同样的,最后一列记录这一行总的个数;
以此类推,直到最后一行,建表完成。
接下来是计算部分,首先定义了一些变量:
ans:编码值-1;
pos:纵向移动,最多移动5次;
siz:字符串长度;
mov:横向移动,最多移动25次;
cnt:记录横向断点;
再来看一下具体如何计算:
首先计算当前行前一行到第一行的最后一列值之和(第一行例外,为0,代码中不体现)
再计算当前行从a列到首字母前一个字母那列之和
到了首字母则向右上方移动一格,计算从那一格到第二个字母前一列的和
到了第二个字母那行再向右上移动...直到到达最后一个字母
为了追求代码简洁因此所有字符串中出现的字符都是不计入的,但是末位要+1,因此最后得到的ans再加一就是正确答案。
下面举个例子:cegik
ans=a[1][26]+a[2][26]++a[3][26]+a[4][26]+a[5][0]+a[5][1]+a[4][3]+a[3][5]+a[2][7]+a[1][9]
编码:ans+1
代码
int main(){
string s;
int dp[7][27];
for(int i=2;i<7;i++)
for(int j=0;j<27;j++)
dp[i][j]=0;
for(int j=0;j<26;j++)
dp[1][j]=1;
dp[1][26]=26;
for(int i=2;i<7;i++)
for(int j=0;j<=26-i;j++){
dp[i][j]=dp[i-1][26];
for(int k=0;k<=j;k++)
dp[i][j]-=dp[i-1][k];
dp[i][26]+=dp[i][j];
}
while(cin>>s){
int siz=s.size(),ans=0,cnt=0;
for(int i=1;i<=siz-1;i++)
ans+=dp[i][26];
for(int pos=0;pos<siz;pos++){
for(int mov=cnt;mov<s[pos]-'a';mov++){
ans+=dp[siz-pos][mov];
cnt++;
}
cnt++;
}
cout << ans+1 << endl;
}
return 0;
}