先来题目链接喽http://poj.org/problem?id=1850
这道题目常见的做法是通过关系推倒导,用dp的方法来做,不过,还有一种更为纯粹的组合数做法;
先把代码贴出来:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
long long int comb(int m,int n) //求组合数C(m,n)
{
int i,j;
long long int a = 1, b = 1;
for(i=m, j=n; j>=1; j--,i--)
{
a = a*i;
b = b*j;
}
return a/b;
}
int main()
{
char c[15];
int m, sum;
int i, j, flag;
scanf("%s", c);
flag = 0;
m = strlen(c);
for(i = 0; i<m-1; i++)
if(c[i] >= c[i+1]){
flag=1;
break;
}
if(flag == 0){
sum = 0;
for(i = 1; i <= m; ++i){
sum += comb(26,i);
}
for(i = 0; i < m; ++i){
sum -= comb(26-(c[i]-'a'+1), m-i);
}
cout << sum << endl;
}
else
putchar('0');
return 0;
}
这里针对思路进行一下说明:
首先,我们知道对于有i个字母的全部组合情况为C(26,i),假设我们的字母数为m,我们先将1~m
所有情况累和。这时所得到的数肯定要比我们要求的答案大一些,我们接下来要做的事情就是将答案之后
的那些组合情况踢出去(核心来了)。
对于每一位而言,要剔除比它大的那些字母所可能产生的组合情况,下面我来举一个栗子:
对于 abcd来说,我们先求出 wxyz的值,然后踢人:
以a开始,先剔除(b~w)xxx的组合情况,然后到了b,剔除(c~x)xx的组合情况,到了c,把(d~y)x的踢了,
最后是d,把(e~z)的踢了。
这样我们就可以清楚地知道,答案+踢出去的人就是全部组合情况,于是乎代码就写成了。
开始未注意到数据范围,写组合数忘了用long long,WA了2h,呜呜呜呜呜....