[HAOI2010] 计数 - 数位dp,组合数

Posted mollnn

tags:

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

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

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

Solution

可重复康托展开

  • 常用数位 dp 套路,枚举哪一位开始比原数小,前方唯一而后方算全排列

  • 回避高精度的全排列数计算,考虑到阶乘最多大约算到 50, 开个因子计数桶,然后在桶上操作就可以了

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 1005;
char str[N];
int n;

int buc[N];

void push(int x) {
    for(int i=2;i<=x;i++) {
        while(x%i==0) buc[i]++, x/=i;
    }
}

void pop(int x) {
    for(int i=2;i<=x;i++) {
        while(x%i==0) buc[i]--, x/=i;
    }
}

int calc(vector <int> v) {
    int sum=0;
    for(int i=0;i<10;i++) sum+=v[i];
    for(int i=2;i<=sum;i++) push(i);
    for(int i=0;i<10;i++) {
        for(int j=2;j<=v[i];j++) pop(j);
    }
    int ans=1;
    for(int i=2;i<=50;i++) while(buc[i]) buc[i]--, ans*=i;
    return ans;
}

signed main() {
    cin>>str+1;
    n=strlen(str+1);
    vector <int> v;
    for(int i=0;i<10;i++) v.push_back(0);
    for(int i=1;i<=n;i++) v[str[i]-'0']++;
    int ans=0;
    for(int i=1;i<=n;i++) {
        for(int j=0;j<str[i]-'0';j++) {
            if(v[j]==0) continue;
            v[j]--;
            ans+=calc(v);
            v[j]++;
        }
        v[str[i]-'0']--;
    }
    cout<<ans<<endl;
}

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

BZOJ2425 [HAOI2010]计数 数位dp

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

[haoi2010]计数

[HAOI 2010] 计数

BZOJ 2302: [HAOI2011]Problem c [DP 组合计数]

BZOJ1833: [ZJOI2010]count 数字计数 (数位dp)