1. 程式人生 > >[ZJOI2010] 數字計數

[ZJOI2010] 數字計數

超過 二維 != 多少 uri 輸入輸出格式 get etc solution

題目描述

給定兩個正整數a和b,求在[a,b]中的所有整數中,每個數碼(digit)各出現了多少次。

輸入輸出格式

輸入格式:

輸入文件中僅包含一行兩個整數a、b,含義如上所述。

輸出格式:

輸出文件中包含一行10個整數,分別表示0-9在[a,b]中出現了多少次。

輸入輸出樣例

輸入樣例#1:

1 99

輸出樣例#1:

9 20 20 20 20 20 20 20 20 20

說明

30%的數據中,\(a<=b<=10^6;\)

100%的數據中,\(a<=b<=10^{12}。\)

Solution

bzoj1883

數位dp,記憶化搜索

主要就是解釋一下變量

len指當前搜到哪一位,當len=0時,就返回當前搜到的值

f表示當前前導0的條件合不合法,初始值是有前導0的,不合法,所以為0
limit表示當前搜索的這一位有沒有限制,即不能超過原數這一數位上的數字,1表示有限制,0表示沒有
sum表示有多少當前已經統計了多少查找的數字
tq表示當前查找的數字是什麽

本來正常情況下,dp數組是要開四維的,\(dp[len][f][limit][sum]\),但是由於本題只在沒有前導0以及當前位所有數字都搜滿的情況下也就是(\(f\) && \(!limit\)),所以可以省去這兩維

提示:關於數組大小,因為我們統計的數字做多只有15位,所以第1維開16即可,第二維因為每次只統計一個數字x,所以最好情況下就是每一位都是x,最多也就是15位,所以也只要開16

Code

#define lol long long
#define Min(a,b) (a)<(b)?(a):(b)
#define Max(a,b) (a)>(b)?(a):(b)
 
using namespace std;
 
const int N=20;

lol dp[N][N];
int bit[N];
 
void in(lol &ans)
{
    ans=0;lol f=1; char i=getchar();
    while(i<'0'||i>'9'){if(i=='-') f=-1; i=getchar();}
    while(i>='0'&&i<='9') ans=(ans<<3)+(ans<<1)+i-'0',i=getchar();
    ans*=f;
}

lol dfs(int len,int f,int limit,lol sum,int tq,lol ans=0) {
    if(!len) return sum;
    if(!limit && f &&  dp[len][sum]!=-1) return dp[len][sum];
    int maxn=limit?bit[len]:9;
    for(int i=0;i<=maxn;i++)
        ans+=dfs(len-1,f||i,limit && i==maxn,sum+((f||i) && (i==tq)),tq);
    if(!limit && f) dp[len][sum]=ans;
    return ans;
}

lol solve(lol a,int tq,int k=0) {
    memset(dp,-1,sizeof(dp));
    while(a) {
        bit[++k]=a%10;
        a/=10;
    }
    return dfs(k,0,1,0,tq);
}
int main()
{
    lol a,b; in(a),in(b);
    for(int i=0;i<10;i++)
        printf("%lld ",solve(b,i)-solve(a-1,i));
    puts("");
    return 0;
}

博主蒟蒻,隨意轉載.但必須附上原文鏈接

http://www.cnblogs.com/real-l/

[ZJOI2010] 數字計數