Codeforces Round #491 (Div. 2) E dfs+计数

好像是第一次自己做出div2的E题耶( •̀ ω •́ ) (虽然是补题)


题目链接

Problem - 991E - Codeforces

 

题意

给出一个可能被看错了的数n,(1<=n<=1e18),问你原本的数有多少种可能。

(注:看到的每一个不同的数字出现次数至少为1,数位可能减少,但不同的数字数量不会减少,顺序可以任意改变,但不能以0开头)

 

思路:

想到了两种思路。

Ⅰ.求出n的位数,统计每一个数字的数量,dfs枚举下一位可能的数是什么,注意有数量的限制。

时间大概是 位数的阶乘... 如果提前算一下就不会tle一发了

 

Ⅱ.枚举出0~9每个数字出现的次数,再根据排列组合公式求出ans。

时间复杂度<1e5  可过

 

code

#include<bits/stdc++.h> 
#define ll long long
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define rrep(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)
#define sc(x) scanf("%d",&(x))
#define scl(x) scanf("%lld",&(x))
#define pb push_back
using namespace std;
const int N = 1005,M = 3e5+10;
const ll inf = 0x3f3f3f3f;
ll n; 
int wei=0;
int cnt[11],tem[11];
ll fac[22];
ll ans;

void init(){
    fac[0]=1;
    rep(i,1,19) fac[i]=fac[i-1]*i;
}

void upd(int tot){
    if(tot>wei) return;
    ll temm=fac[tot];
    ll subb=fac[tot-1];
    rep(i,0,9){
        temm/=fac[tem[i]];
    }
    ans+=temm;
    if(cnt[0]==0){
        subb=0;
        return;
    }
    rep(i,0,9){
        if(i==0) subb/=fac[tem[i]-1];
        else subb/=fac[tem[i]];
    }
    ans-=subb;
//    cout<<temm<<" "<<subb<<" "<<ans<<endl;
}

void dfs(int num,int tot){  //枚举出现次数 
    if(num==10){
        upd(tot);
        return;
    }
    if(cnt[num]==0) dfs(num+1,tot);
    rep(i,1,cnt[num]){
        tem[num]=i;
        num+=1,tot+=i;
        dfs(num,tot);
        num-=1,tot-=i;
    }
}

int main(){
    init();
    scl(n);
    ll nn=n;
    while(nn){
        cnt[nn%10]++;
        nn/=10;
        wei++;
    }
    dfs(0,0);
    cout<<ans<<endl;
    return 0;
} 
View Code

 

只要学好暴力,就啥题都不怕

posted @ 2021-10-20 18:25  starlightlmy  阅读(40)  评论(0)    收藏  举报