[HAOI2010] 計數
阿新 • • 發佈:2018-07-17
continue 不一定 mes 無限 span 排列 一個數 main ...
題目描述
你有一組非零數字(不一定唯一),你可以在其中插入任意個0,這樣就可以產生無限個數。比如說給定{1,2},那麽可以生成數字12,21,102,120,201,210,1002,1020,等等。
現在給定一個數,問在這個數之前有多少個數。(註意這個數不會有前導0).
輸入輸出格式
輸入格式:
只有1行,為1個整數n.
輸出格式:
只有整數,表示N之前出現的數的個數。
輸入輸出樣例
輸入樣例#1:
1020
輸出樣例#1:
7
說明
n的長度不超過50,答案不超過2^63-1.
題解
組合數學(+數位DP?)
可以不省略前導\(0\),轉換為這個數的全排列有多少小於\(N\)
先遞推組合數,然後每次循環每一位可以是多少,累答案
累答案就先放0,在放1,一直到9.如果有m位,答案就是:$C(m, cnt_0) * C(m-cnt_0, cnt_1) * C(m-cnt_0-cnt_1, cnt_2) * ... $
#include <iostream> #include <cstdio> #include <cstring> using namespace std; typedef long long LL; int n, cnt[10], num[55]; char s[55]; LL c[60][60], ans; void init_c() { const int l = 50; for(int i = 0; i <= l; ++ i) { c[i][0] = c[i][i] = 1; for(int j = 1; j < i; ++ j) c[i][j] = c[i-1][j] + c[i-1][j-1]; } } LL _count(int m) { LL ans = 1; for(int i = 0; i < 10; m -= cnt[i ++]) ans *= c[m][cnt[i]]; return ans; } int main() { cin >> s; n = strlen(s); init_c(); for(int i = 0; i < n; ++ i) cnt[num[i] = s[i] - '0'] ++; for(int i = 0; i < n; ++ i) { for(int j = 0; j < num[i]; ++ j) { if(!cnt[j]) continue; -- cnt[j]; ans += _count(n - 1 - i); ++ cnt[j]; } cnt[num[i]] --; } printf("%lld\n", ans); return 0; }
[HAOI2010] 計數