BZOJ2425 [HAOI2010]计数

根数位DP思想差不多,但是根本不用DP……

先枚举不到n位的,组合数算算,然后还是从高位到低位逐位确定,组合数算算就行了

组合数算算嘛……就是你确定一下最高位,然后剩下的可以随意摆放,就是阶乘,然后再除以每个数字个数的阶乘就行了

额,这好像不是组合数啊-_-

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<map>
#include<set>
#include<bitset>
#include<queue>
#include<stack>
using namespace std;
#define MAXN 1010
#define MAXM 1010
#define INF 1000000000
#define MOD 1000000007
#define eps 1e-8
#define ll long long
struct data{
    int a[10];
    data(){
        memset(a,0,sizeof(a));
    }
};
data ch(data x,int y,int z){
    x.a[y]+=z;
    return x;
}
char s[MAXN];
int n,m;
ll ans;
data now;
int t[MAXN];
void ADD(int x,int y){
    int i;
    for(i=2;x!=1;i++){
        while(!(x%i)){
            t[i]+=y;
            x/=i;
        }
    }
}
void add(int x,int y){
    int i,j;
    for(i=2;i<=x;i++){
        ADD(i,y);
    }
}
ll cal(data x,int y){
    int i,j;
    if(!x.a[y]){
        return 0;
    }
    memset(t,0,sizeof(t));
    int N=0;
    for(i=0;i<=9;i++){
        N+=x.a[i];
    }
    add(N-1,1);
    ADD(x.a[y],1);
    for(i=0;i<=9;i++){
        add(x.a[i],-1);
    }
    ll re=1;
    for(i=1;i<=50;i++){
        for(j=1;j<=t[i];j++){
            re*=i;
        }
    }
    return re;
}
int main(){
    int i,j;
    scanf("%s",s+1);
    n=strlen(s+1);
    for(i=1;i<=n;i++){
        s[i]-='0';
        if(s[i]){
            m++;
            now=ch(now,s[i],1);
        }
    }
    for(i=1;i<=n/2;i++){
        swap(s[i],s[n-i+1]);
    }
    for(i=m;i<n;i++){
        for(j=1;j<=9;j++){
            ans+=cal(ch(now,0,i-m),j);
        }
    }
    now=ch(now,0,n-m);
    for(j=1;j<s[n];j++){
        ans+=cal(now,j);
    }
    now=ch(now,s[n],-1);
    for(i=n-1;i;i--){
        for(j=0;j<s[i];j++){
            ans+=cal(now,j);
        }
        now=ch(now,s[i],-1);
    }
    printf("%lld\n",ans);
    return 0;
}
 
/*
1020
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值