poj-1850

// 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顺序,顺序已经提前确定了)。

有了上面的转化,下面的纯粹就是 利用 加法原理来逐位进行处理和相加了.

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值