一本通1591数字计数

1591:数字计数

时间限制: 1000 ms         内存限制: 524288 KB

题目描述

原题来自:ZJOI 2010

给定两个正整数 a 和 b,求在 [a,b] 中的所有整数中,每个数码 (digit) 各出现了多少次。

输入格式

仅包含一行两个整数 a,b,含义如上所述。

输出格式

包含一行 10 个整数,分别表示 09 在 [a,b] 中出现了多少次。

样例

样例输入

1 99

样例输出

9 20 20 20 20 20 20 20 20 20

数据范围与提示

30% 的数据中,1ab10^6;
100% 的数据中,1ab10^12。

sol:被初始化搞得很蛋碎,忘了初始化就会挂的相当惨qaq

dp[i][j][k][0,1][0,1]表示前i个位置有k个j的方案数(另两个分别是上界和前导0)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll read()
{
    ll s=0;
    bool f=0;
    char ch=' ';
    while(!isdigit(ch))
    {
        f|=(ch=='-');
        ch=getchar();
    }
    while(isdigit(ch))
    {
        s=(s<<3)+(s<<1)+(ch^48);
        ch=getchar();
    }
    return (f)?(-s):(s);
}
#define R(x) x=read()
inline void write(ll x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x<10)
    {
        putchar(x+'0');
        return;
    }
    write(x/10);
    putchar((x%10)+'0');
    return;
}
inline void writeln(ll x)
{
    write(x);
    putchar('\n');
    return;
}
#define W(x) write(x),putchar(' ')
#define Wl(x) writeln(x)
int Num[20];
ll dp[20][10][20][2][2];//前i个位置有k个j的方案数
inline ll dfs(int Weiz,int Shuz,int Ges,bool Shangj,bool Qiand0)
{
    if(dp[Weiz][Shuz][Ges][Shangj][Qiand0]) return dp[Weiz][Shuz][Ges][Shangj][Qiand0];
    if(Weiz==1) return (dp[Weiz][Shuz][Ges][Shangj][Qiand0]=Ges);
    int i,Up=(Shangj)?(Num[Weiz-1]):9;
    for(i=0;i<=Up;i++)
    {
        bool Bo1=(Shangj&&i==Up),Bo2=(Qiand0&&i==0);
        if(Shuz||(!Bo2)) dp[Weiz][Shuz][Ges][Shangj][Qiand0]+=dfs(Weiz-1,Shuz,Ges+(i==Shuz),Bo1,Bo2);
        else dp[Weiz][Shuz][Ges][Shangj][Qiand0]+=dfs(Weiz-1,Shuz,Ges,Bo1,Bo2);
    }
    return dp[Weiz][Shuz][Ges][Shangj][Qiand0];
}
inline ll Solve(ll n,int Shuz)
{
    if(n==0) return 0;
    *Num=0;
//    printf("n=%lld ",n);
    while(n)
    {
        Num[++*Num]=n%10;
        n/=10;
    }
    int i;
    ll ans=0;
    ans+=dfs(*Num,Shuz,0,0,1);
    for(i=1;i<Num[*Num];i++) ans+=dfs(*Num,Shuz,(Shuz==i)?1:0,0,0);
    ans+=dfs(*Num,Shuz,(Shuz==Num[*Num])?1:0,1,0);
//    printf("ans=%lld\n",ans);
    memset(dp,0,sizeof dp);
    memset(Num,0,sizeof Num);
    return ans;
}
int main()
{
    ll l,r;
    int i;
    R(l); R(r);
    for(i=0;i<9;i++) W(Solve(r,i)-Solve(l-1,i));
    Wl(Solve(r,9)-Solve(l-1,9));
    return 0;
}
/*
input
1 99
output
9 20 20 20 20 20 20 20 20 20

input
218635 261553
output
17882 18801 69801 26887 26891 26840 18401 16882 17247 17882
*/
View Code

猜你喜欢

转载自www.cnblogs.com/gaojunonly1/p/10363008.html