zznu 1255 数字统计(数位DP, 数学方法)
最近在学数位DP, 感觉还是满有收获的! 做了几个题之后想起来自己OJ上曾经做的一道题,以前是用数学方法写的,现在改用数位DP来写了一遍。
题目:
1255: 数字统计
时间限制: 1 Sec 内存限制: 128 MB提交: 31 解决: 4
[提交][状态]
题目描述
一本书的页码从自然数1 开始顺序编码直到自然数n。书的页码按照通常的习惯编排,
每个页码都不含多余的前导数字0。例如,第6 页用数字6 表示,而不是06 或006 等。数
字计数问题要求对给定书的总页码n,计算出书的全部页码中分别用到多少次数字0,1,
2,…,9。
输入
给出表示书的总页码的整数n(1≤n≤2^31-1)
输出
输出10行,在第k行输出页码中用到数字k-1 的次数,k=1,2,…,10。
样例输入
11
样例输出
1
4
1
1
1
1
1
1
1
1
链接:http://acm.zznu.edu.cn/problem.php?id=1255
数学方法:
其实就是假设每一位是0-9然后进行判断, 计算出结果
#include<stdio.h> int Slove(int num,int k) { int L, R, M, P = 1, a = num; int sum = 0; while(a) { R = num%P; M = a%10; L = a/10; if(k) { if(k < M) sum += (L+1)*P; else if(k == M) sum += L*P + (R+1); else sum += L*P; } else { if(a<10) break; if(k == M) sum += (L-1)*P + (R+1); else sum += L*P; } P *= 10; a /= 10; } return sum; } int main() { int n, ans; int i; scanf("%d",&n); for(i=0; i<=9; i++) { ans = Slove(n,i); printf("%d\n",ans); } return 0; }
数位DP;
这个就比较通用了, 就是套模版, 对数据的处理上 稍加注意, 然后把状态确定好。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; LL dp[20][20][11][2];//dp[位数][数字出现的次数][这个数字是多少][首位是否是0] int bit[20]; LL dfs(int pos,int cou,int num,int flag,bool is0) { if( pos == -1 ) { return cou; } if(!flag && dp[pos][cou][num][is0] != -1) return dp[pos][cou][num][is0]; LL ans = 0; int end = flag? bit[pos]: 9; for(int i=0; i<=end; i++) { if(i == num && !(is0 && i == 0) ) ans += dfs(pos-1, cou+1, num, flag && i == end, is0 && i == 0 ); else ans += dfs(pos-1, cou, num, flag && i == end, is0 && i == 0 ); } if(!flag) dp[pos][cou][num][is0] = ans; return ans; } void solve(LL n) { int len = 0, i, m = n; LL ans; while(n) { bit[len++] = n%10; n /= 10; } for(i=0; i<=9; i++) { ans = dfs(len-1, 0, i, 1, 1); printf("%lld\n", ans); } // printf("\n\n\n"); } int main() { LL a; memset(dp, -1 ,sizeof(dp)); while(scanf("%lld", &a) != EOF) { solve(a); } // printf("\n\n\n"); return 0; }