【BZOJ 1833】【數位DP】 ZJOI2010 count【求在[a,b]中的所有整數中,每個數碼(digit)各出現了多少次】
阿新 • • 發佈:2019-01-29
描述:
1833: [ZJOI2010]count 數字計數
Time Limit: 3 Sec Memory Limit: 64 MBSubmit: 2766 Solved: 1226
[Submit][Status][Discuss]
Description
給定兩個正整數a和b,求在[a,b]中的所有整數中,每個數碼(digit)各出現了多少次。Input
輸入檔案中僅包含一行兩個整數a、b,含義如上所述。Output
輸出檔案中包含一行10個整數,分別表示0-9在[a,b]中出現了多少次。Sample Input
1 99Sample Output
9 20 20 20 20 20 20 20 20 20HINT
30%的資料中,a<=b<=10^6;
100%的資料中,a<=b<=10^12。
Source
題意:
求[a,b]間所有的整數中0~9每個數字出現了幾次
思路:
設dp[i][j][k]表示長度為i,開頭為j的數中k的個數
分開統計答案,對於位數小於當前數的直接全部加上,剩餘的拆分統計
程式碼:
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=20; ll a,b; ll dp[maxn][maxn][maxn];//長度為i,開頭為j的數中k的個數 ll bin[maxn];//i位中所有首位為i的數的個數 ll res[maxn];//記錄0~9個數 int d[maxn]; void init(){//遞推計算出每個整數 bin[1]=1; for(int i=2; i<=13; i++)bin[i]=bin[i-1]*10; for(int i=0; i<=9; i++)dp[1][i][i]=1; for(int i=2; i<=13; i++) for(int j=0; j<=9; j++) for(int z=0; z<=9; z++){ for(int k=0; k<=9; k++) dp[i][j][z]+=dp[i-1][k][z]; dp[i][z][z]+=bin[i-1]; } } void solve(ll x,int flag){ //計算1~x的所有整數 int dnum=0;//記錄當前數的位數 ll tmpn=x; memset(d, 0, sizeof(d)); while(x){ d[++dnum]=x%10; x/=10;} for(int i=1; i<=dnum-1; i++)//位數小於當前數的位數 for(int j=1; j<=9; j++) for(int k=0; k<=9; k++) res[k]+=(dp[i][j][k]*flag); int tmp=dnum; while(tmp){//位數等於當前數的位數,拆分統計這裡可以舉一個120的例子仔細思考一下過程 for(int i=0; i<d[tmp]; i++){ if(!i && tmp==dnum)continue;//不能重複計算 for(int j=0; j<=9; j++) res[j]+=(dp[tmp][i][j]*flag); } res[d[tmp]]+=(tmpn%bin[tmp]+1)*flag; tmp--; } } int main(){ /* #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif*/ init(); scanf("%lld%lld",&a,&b); solve(b, 1);solve(a-1, -1); for(int i=0; i<=9; i++) printf("%lld%c",res[i],i==9?'\n':' '); return 0; }