目录

P2518-[HAOI2010]计数

P2518-[HAOI2010]计数

题目:

题目描述:

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

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

输入格式:

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

输出格式:

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

样例:

样例输入1:

1
2

1020

样例输出1:

1
2

7

思路:

我们发现$a_1个1, a_2个2, a_3个3\cdots$的可重集排列的答案: 记m为数的总数, n为数的总类. $\tbinom{m}{a_1}+\tbinom{m-a_1}{a_2}+\tbinom{m-a_1-a_2}{a_3}+\cdots$

实现:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// Problem: P2518 [HAOI2010]计数
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P2518
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// Author: Ybw051114
//
// Powered by CP Editor (https://cpeditor.org)

#include "ybwhead/ios.h"
const int maxn = 101;
int a[maxn];
long long c[maxn][maxn];
long long calc(int nw)
{
    long long ans = 1;
    for (int i = 0; i <= 9; i++)
    {
        ans *= c[nw][a[i]];
        nw -= a[i];
    }
    // yout << ans << endl;
    return ans;
}
int main()
{
    string s;
    yin >> s;
    int n = s.size();
    c[0][0] = 1;
    for (int i = 1; i <= n; 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];
        }
    }
    for (int i = 0; i < s.size(); i++)
        a[s[i] - '0']++;
    long long ans = 0;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < s[i] - '0'; j++)
        {
            a[j]--;
            ans += calc(n - i - 1);
            a[j]++;
        }
        a[s[i] - '0']--;
    }
    yout << ans << endl;
    return 0;
}