LG-P2518 [HAOI2010]計數
阿新 • • 發佈:2018-11-05
P2518 [HAOI2010]計數
題目連結
題目描述
你有一組非零數字(不一定唯一),你可以在其中插入任意個0,這樣就可以產生無限個數。比如說給定{1,2},那麼可以生成數字12,21,102,120,201,210,1002,1020,等等。
現在給定一個數,問在這個數之前有多少個數。(注意這個數不會有前導0).
輸入格式:
只有1行,為1個整數n.
輸出格式:
只有整數,表示N之前出現的數的個數。
輸入樣例:
1020
輸出樣例:
7
說明
n的長度不超過50,答案不超過2^63-1.
題解
首先想到DFS,結果看看資料範圍瞬間就萎了。
如果我們確定高位小於 N,那麼剩餘的位數,就用剩下的數進行排列就好了。
從最高位向低位列舉相等的位,然後找一個小於當前位的數字放在當前位,剩下的排列即可。
程式碼
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=55;
#define LL long long
LL c[maxn][maxn],ans=0;
int a[maxn],h[15],n;
char s[maxn];
LL C(int n,int m)
{
if (n==m|| !m) return 1;
if (n<m) return 0;
if (m==1) return n;
if (c[n][m]) return c[n][m];
return c[n][m]=C(n-1,m)+C(n-1,m-1);
}
LL SUM()
{
LL ret=1;int m=n;
for (int i=0;i<10;++i) ret*=C(m,h[i]),m-=h[i];
return ret;
}
int main()
{
// freopen("st.in","r",stdin);freopen("st.out","w",stdout);
scanf("%s" ,s);n=strlen(s);
for (int i=0;i<n;++i) ++h[a[i]=s[i]-'0'];
for (int i=0,R=n;i<R;++i)
{
--n;
for (int j=a[i]-1;j>=0;--j)
{
if (!h[j]) continue;
--h[j];
ans+=SUM();
++h[j];
}
--h[a[i]];
}
printf("%lld\n",ans);
return 0;
}