码迷,mamicode.com
首页 > 其他好文 > 详细

[HAOI2010] 计数

时间:2018-07-17 19:53:41      阅读:213      评论:0      收藏:0      [点我收藏+]

标签:const   转换   个数   生成   char   ios   +=   \n   lld   

题目描述

你有一组非零数字(不一定唯一),你可以在其中插入任意个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\n", ans);
    return 0;
}

[HAOI2010] 计数

标签:const   转换   个数   生成   char   ios   +=   \n   lld   

原文地址:https://www.cnblogs.com/cute-hzy/p/9325460.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!