// 160K 0MS C++
#include "stdio.h"
#include "string.h"
char str[12];
int C[32][32];
void getCombination() {
for (int n = 0; n <= 32; n++) {
for (int m = 0; m <= n; m++) {
if (m == 0) { // choose nothing
C[n][m] = 1;
} else if (n == 0) { // nothing to choose
C[n][m] = 0;
} else if (m > n) {
C[n][m] = 0;
} else if (m == n) {
C[n][m] = 1;
} else {
C[n][m] = C[n-1][m] + C[n-1][m-1];
// printf("C %d %d is %d\n",n, m, C[n][m]);
}
}
}
}
char ifValid(char * str) {
int length = strlen(str);
for (int i = 0; i <= length - 2; i++) {
if (str[i] >= str[i+1]) {
return 0;
}
}
return 1;
}
int getNumber(char * str) {
int sum = 0;
int length = strlen(str);
if (!ifValid(str)) {
return 0;
}
for (int i = 1; i <= length - 1; i++) {
sum += C[26][i];
}
// printf("S1 %d\n", sum);
for (int i = 0; i <= length - 1; i++) {
int curVal = str[i] - 'a';
// printf("curVal %d\n", curVal);
if (i == 0) {
for (int k = curVal; k >= 1; k--) {
sum += C[26 - k][length - 1 - i];
// printf("1 %d\n", sum);
}
} else {
char prev = str[i-1];
int minChar = prev - 'a' + 1 + 1;
// printf("minChar %d\n", minChar);
for (int k = curVal + 1 - 1; k >= minChar; k--) {
sum += C[26 - k][length - 1 - i];
// printf("2 %d\n", sum);
}
}
}
// printf("S2 %d\n", sum);
return sum + 1;
}
int main() {
getCombination();
while(scanf("%s", str) != EOF) {
int res = getNumber(str);
printf("%d\n", res);
if (!res) {
break;
}
}
}1496 一样的解,买一送一.
基本思路其实和之前的3252是一样的,不过一开始没有成功的抽象出 组合数C 这个思路,后来还是看了别的题解才领悟,唉,组合数学要看看了,并且发现这类题正好是自己的软肋,虽然用的思路和技法都没啥难的,但是难在逻辑的繁琐和各种逻辑符号之间转换以及对边界条件的考虑,是最切中我要害的地方.
关键的转化思路就是, 对于 以某个字母开头的数, 比如 dXXXX, 会有多少中可能的组合? 而题目也明确指出了 一个有效的数 其高位的字母 要比 低位的字母小:
及 ab 是有效的, 而ba是无效的(注意题目要求无效数输出0), 那么 对于 dXXX, 这3个X可能的取值组合就是 C(3, 22), 即在比d大的22的字母中找3个数字组合的数量(为什么是组合? 因为对于三个具体字母的任何排列,在这道题里面都体现不出差异,题目都会固定的按照从小到大的顺序来排, e.g: 取了 fyz 三个字母,无论这3个字母如何排列, 最后都会变成 fyz这种排列, 因此排列在这里失去了意义,只需找到3个数即可,不care顺序,顺序已经提前确定了)。
有了上面的转化,下面的纯粹就是 利用 加法原理来逐位进行处理和相加了.

228

被折叠的 条评论
为什么被折叠?



