[省选前题目整理][BZOJ 1833][ZJOI 2010]count 数字计数(数位DP)

题目链接

http://www.lydsy.com/JudgeOnline/problem.php?id=1833

思路

http://blog.csdn.net/qpswwww/article/details/43982403

代码

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

#define MAXN 1000

using namespace std;

typedef long long int LL;

LL ans[10]; //ans[i]=数位i在[L,R]中的出现次数
LL pow[13];

void solve(LL x,int sign) //sign为1在答案里加,sign为-1在答案里减
{
    if(x==-1) //特判
    {
        ans[0]++;
        return;
    }
    //求数字1~9的出现次数
    for(LL j=1;j<=9;j++)
        for(LL i=1;pow[i-1]<=x;i++) //枚举第i位
        {
            LL len=i-1; //len是该数字右边那部分的长度
            LL L=x/pow[i],R=x%pow[i-1]; //L是该数字左边那部分,R是该数字右边那部分
            LL t=(x/pow[i-1])%10; //t是x第i位的数位
            if(j>t) ans[j]+=L*pow[len]*sign;
            else if(j<t) ans[j]+=(L+1)*pow[len]*sign;
            else if(j==t) ans[j]+=(L*pow[len]+R+1)*sign;
        }
    //求0的出现次数
    for(LL i=1;pow[i-1]<=x;i++)
    {
        LL len=i-1; //len是该数字右边那部分的长度
        LL L=x/pow[i],R=x%pow[i-1]; //L是该数字左边那部分,R是该数字右边那部分
        LL t=(x/pow[i-1])%10; //t是x第i位的数位
        if(t>0) ans[0]+=L*pow[len]*sign;
        else if(t==0) ans[0]+=((L-1)*pow[len]+R+1)*sign;
    }
}

int main()
{
    LL a,b;
    scanf("%lld%lld",&a,&b);
    pow[0]=1;
    for(int i=1;i<13;i++) pow[i]=pow[i-1]*10;
    solve(b,1);
    solve(a-1,-1);
    for(int i=0;i<=9;i++) printf("%lld%c",ans[i],i==9?'\n':' ');
    return 0;
}

你可能感兴趣的:([省选前题目整理][BZOJ 1833][ZJOI 2010]count 数字计数(数位DP))