• P2602 [ZJOI2010]数字计数


    P2602 [ZJOI2010]数字计数

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

    Solution

    一眼识数位dp
    (dp[i][j]) 对某个指定的数码, 填了 (i) 位, 其中有 (j) 位填了特定数码的 总数码数
    然后分一下前导零, 最高位, 数位dp即可
    看代码

    Code

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #include<climits>
    #define LL long long
    #define REP(i, x, y) for(LL i = (x);i <= (y);i++)
    using namespace std;
    LL RD(){
        LL out = 0,flag = 1;char c = getchar();
        while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
        while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
        return flag * out;
        }
    const LL maxn = 19;
    LL num[maxn];
    LL mem[maxn];
    LL dp[maxn][maxn];//填完i位,填了j个给定数码的数码总数
    LL a, b;
    LL DP(LL Index, LL sum, LL state, bool zero, bool limit){
    	if(Index == 0)return sum;//填完一组新的,总数累加sum
    	if(!zero && !limit && dp[Index][sum] != -1)return dp[Index][sum];
    	LL ans = 0, up = limit ? num[Index] : 9, add = 0;
    	REP(i, 0, up){
    		if(state != 0 || (state == 0 && !zero))add = (i == state);
    		ans += DP(Index - 1, sum + add, state, zero && i == 0, limit && i == num[Index]);
    		}
    	if(!zero && !limit)dp[Index][sum] = ans;
    	return ans;
    	}
    LL get_num(LL x, LL state){
    	LL len = 0;
    	while(x){
    		num[++len] = x % 10;
    		x /= 10;
    		}
    	return DP(len, 0, state, 1, 1);
    	}
    void init(){
    	a = RD(), b = RD();
    	memset(dp, -1, sizeof(dp));
    	}
    void solve(){
    	REP(i, 0, 9){
    		printf("%lld ", get_num(b, i) - get_num(a - 1, i));
    		}
    	puts("");
    	}
    int main(){
    	init();
    	solve();
    	return 0;
    	}
    
  • 相关阅读:
    XML&nbsp; XmlDocument
    程序集报错
    程序打开网页
    写入文件txt
    读取文件txt
    MSM8953中Android系统添加启动脚本.rc文件
    SELinux基础知识
    嵌入式Linux设备查看USB相关信息
    Linux内核态文件读写相关函数API
    C语言中sscanf()函数相关用法
  • 原文地址:https://www.cnblogs.com/Tony-Double-Sky/p/9921906.html
Copyright © 2020-2023  润新知