[HAOI2010] 计数

Posted cute-hzy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[HAOI2010] 计数相关的知识,希望对你有一定的参考价值。

题目描述

你有一组非零数字(不一定唯一),你可以在其中插入任意个0,这样就可以产生无限个数。比如说给定{1,2},那么可以生成数字12,21,102,120,201,210,1002,1020,等等。

现在给定一个数,问在这个数之前有多少个数。(注意这个数不会有前导0).

输入输出格式

输入格式:

只有1行,为1个整数n.

输出格式:

只有整数,表示N之前出现的数的个数。

输入输出样例

输入样例#1:

1020

输出样例#1:

7

说明

n的长度不超过50,答案不超过2^63-1.

题解

组合数学(+数位DP?)

可以不省略前导(0),转换为这个数的全排列有多少小于(N)

先递推组合数,然后每次循环每一位可以是多少,累答案

累答案就先放0,在放1,一直到9.如果有m位,答案就是:$C(m, cnt_0) * C(m-cnt_0, cnt_1) * C(m-cnt_0-cnt_1, cnt_2) * ... $

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

typedef long long LL;

int n, cnt[10], num[55];
char s[55];
LL c[60][60], ans;

void init_c() {
    const int l = 50;
    for(int i = 0; i <= l; ++ i) {
        c[i][0] = c[i][i] = 1;
        for(int j = 1; j < i; ++ j)
            c[i][j] = c[i-1][j] + c[i-1][j-1];
    }
} 

LL _count(int m) {
    LL ans = 1;
    for(int i = 0; i < 10; m -= cnt[i ++])
        ans *= c[m][cnt[i]];
    return ans;
} 

int main() {
    cin >> s;
    n = strlen(s);
    init_c();
    for(int i = 0; i < n; ++ i) 
        cnt[num[i] = s[i] - '0'] ++;
    for(int i = 0; i < n; ++ i) {
        for(int j = 0; j < num[i]; ++ j) {
            if(!cnt[j]) continue;
            -- cnt[j];
            ans += _count(n - 1 - i);
            ++ cnt[j];
        }
        cnt[num[i]] --;
    }
    printf("%lld
", ans);
    return 0;
}

以上是关于[HAOI2010] 计数的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 2425 [HAOI2010]计数 dp+组合计数

[HAOI2010] 计数

[haoi2010]计数

洛谷P2518 [HAOI2010]计数

P2518 [HAOI2010]计数

P2518 [HAOI2010]计数