POJ-1850-Code-组合数学

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;
}










你可能感兴趣的:(POJ-1850-Code-组合数学)