1. 程式人生 > >1850】Code (組合數學,字串另類排序)

1850】Code (組合數學,字串另類排序)

題幹:

Transmitting and memorizing information is a task that requires different coding systems for the best use of the available space. A well known system is that one where a number is associated to a character sequence. It is considered that the words are made only of small characters of the English alphabet a,b,c, ..., z (26 characters). From all these words we consider only those whose letters are in lexigraphical order (each character is smaller than the next character).  The coding system works like this:  • The words are arranged in the increasing order of their length.  • The words with the same length are arranged in lexicographical order (the order from the dictionary).  • We codify these words by their numbering, starting with a, as follows:  a - 1  b - 2  ...  z - 26  ab - 27  ...  az - 51  bc - 52  ...  vwxyz - 83681  ...  Specify for a given word if it can be codified according to this coding system. For the affirmative case specify its code. 

Input

The only line contains a word. There are some constraints:  • The word is maximum 10 letters length  • The English alphabet has 26 characters. 

Output

The output will contain the code of the given word, or 0 if the word can not be codified.

Sample Input

bf

Sample Output

55

題目大意:

按一定規則編纂了字典序:

字典中的各字串中的字母保證嚴格按升序排列。 長度小的一定在長度大的前面,長度相同時,按照真正的字典序。 給出一個字串,求該字串在字典中的編號,若字典中沒有(字母不按升序排)則輸出0。 

解題報告:

一個題解

對於不同的小寫字母,嚴格升序組成的一組序列,分別代表從1~n的數值。

這題關鍵是求組合的數值C。對於方法,並不是太難,分兩種情況

1.當長度小於給出的字串L時,對於字串長度為1的字串總共代表的數字的量就是C(26,1),對於長度為2的字串總共代表的數字的量就是C(26,2),一次類推,直到C(26,L-1)。

2.對於長度等於L的,從最開頭的字元s[0]開始,對於比這個字元嚴格小的,如果有一個,我們可以有C('z'-s[0], L-1)個,'z'-s[0] 是因為題意已經說明該字串每個位置是嚴格遞增的。如果在這個位置,還能找到別s[0]嚴格小的,則再加上。

再遍歷到後面的字元s[i],對於比這個字元嚴格小的,我們依然可以找到C('z'-s[0], L-i-1)個。一直到最後一個字元,這樣,所有結果的總和,就是結果。

對於1中的原理如下:

以兩位的串為例,有ab~az,bc~cz,……那麼有組合數

C_{25}^{1}+C_{24}^{1}+C_{23}^{1}+\cdots +C_{2}^{1}+C_{1}^{1} = C_{26}^{2}

遞推出這個公式,需要結合組合裡的一個很常用的式子

C_{n}^{k} =C_{n-1}^{k}+C_{n-1}^{k-1}

後面的依此類推。有大佬也指出,既然你是升序,那麼只要你有幾位,你就選幾個出來,那麼它的嚴格升序排列只有一種,所以就是C(26,L),就是在長度為L下的所有組合數。

然後利用上面的式子進行遞推,求出所有的26以內的所有組合數,再直接利用求結果即可。

AC程式碼:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
#define fi first
#define se second
using namespace std;
const int MAX = 2e5 + 5;
ll C[33][33];
ll n,ans;
char s[33];
int main()
{
	C[0][0]=1;
	for(int i = 1; i<=30; i++) {
		C[i][0] = 1;
		for(int j = 1; j<=30; j++) {
			C[i][j] = C[i-1][j] + C[i-1][j-1];
		}
	}
	while(~scanf("%s",s)) {
		ll ans = 0;
		int len = strlen(s);
		bool flag = 1;
		for(int i = 0; i<len-1; i++) {
			if(s[i] >= s[i+1]) {
				flag = 0;break;
			}
		}
		if(flag == 0) {
			puts("0");
			continue;
		}
		//之前長度的 
		for(int i = 1; i<len; i++) {
			ans += C[26][i];
		}
		//當前字元開始計算 
		for(int i = 0; i<len; i++) {
			char cur;
			if(!i) cur = 'a';
			else cur = s[i-1]+1;
			while(cur < s[i]) {
				ans += C[26-(cur-'a')-1][len-i-1];
				cur++;
			} 
			
		}
		printf("%lld\n",ans+1);	
	}
	return 0 ;
 }