http://poj.org/problem?id=1850
本题其实并不难。。。自己给自己吓到了。。看了复杂的题解。。。
和3252的思路一样,要求当前字符串的位置,设当前长度为x
1、先求 len<x的字符串数量,
2、再求len==x,比当前字符串小的数量
显然,要求长度为k,的字符串,满足严格增序的种类,就是 C(26,k)【直接从a,b,c.....z选k个】
把 长度小于x的 所有i,累加C【26】【i】;// 得到第一部分值
那么对于第二部分,
同长度下,如:bceg
首字母为b, 那么显然之前可以有 以a开头的,剩下部分长度为3的所有字符串,
即: 要加上 所有 s[0]之前,‘a’之后的字母开头的,长度为x-1的字符串
其余非首字母
如e, 显然此时要枚举的字符串前两位是bc, 那么我们只需要第三位 大于c且小于e,剩余部分随意
也就是 从s[i-1]+1到s[i]-1,中 的 某个字母作为开头,剩下长度为len-i-1的字符串【任意选】
至于这个任意选也很好处理,如果 开头的是c,那么任意选就是从 26-3个字母里面选择 len-i-1个
C【26-3】【len-i-1】
#include <cstdio> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <queue> #include <map> #include <set> #include <stack> #include <iostream> using namespace std; __int64 inf=15; double eps=0.000001; __int64 n,m; char tm[15]; __int64 cc[100][100]; void pre() { __int64 i,j; for (i=0;i<=40;i++) cc[i][0]=1; for (i=1;i<=40;i++) for(j=1;j<=40;j++) cc[i][j]=(cc[i-1][j-1]+cc[i-1][j]); } int check(char *s,int len) { for (int i=1;i<len;i++) { if (s[i]<=s[i-1]) return 0; } return 1; } int main() { pre(); scanf("%s",tm); int len=strlen(tm); int ret=check(tm,len); if (ret==0) { printf("0\n"); return 0;} __int64 sum=0,i,j; for (i=1;i<len;i++)//累计所有长度小于len的字符串个数 sum+=cc[26][i]; //接下来算长度等于len的字符串个数 if (tm[0]>'a') { __int64 tmp=0; for (i=1;i<=tm[0]-'a'-1+1;i++) //tm[0]-'a'+1得到该字母对应数字,减一表示按照严格递增 tmp+=cc[26-i][len-1]; sum+=tmp; } for (i=1;i<len;i++) { if (tm[i]-1-tm[i-1]>0) { __int64 tmp=0; for (j=tm[i-1]-'a'+1+1;j<=tm[i]-'a'+1-1;j++) //tm[i-1]-'a'+1得到该字母对应数字,加一表示按照严格递增,不与i-1个字符重复,其他同理 tmp+=cc[26-j][len-i-1]; sum+= tmp; } } printf("%I64d\n",sum+1); return 0; }