1. 程式人生 > >POJ-1850-Code-組合數學

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