Codeforces Round #491 (Div. 2) E dfs+计数
好像是第一次自己做出div2的E题耶( •̀ ω •́ ) (虽然是补题)
题目链接
题意
给出一个可能被看错了的数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; }
只要学好暴力,就啥题都不怕

浙公网安备 33010602011771号