[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] 计数的主要内容,如果未能解决你的问题,请参考以下文章