[bzoj 1833] [ZJOI2010]count 数字计数:数位DP
来源:互联网 发布:mac版chrome好用吗 编辑:程序博客网 时间:2024/05/21 22:50
题意:求[a, b]之间的所有整数中各个数码出现了多少次。(1<=a<=b<=10^12,a, b是整数)
考虑[1, x)内各个数码出现了多少次。设f[i][j][k]
为以j开头的(i+1)位十进制串中k出现的次数,递推。
[1, x)内的数可分为三类:
1. 位数少于x。
2. 最高位小于x。
3. 和x有公共的前缀。
分类统计,第二、三类可以合并。设现在考虑从高往低第k位,则f
数组包含k及其右边的数码,k左边的数码还需要单独计算。
看了Po姐的题解,感觉比我写的要美……
f[i][j][k]
可简化为f[i]
(依然允许前导0),因为每个数码出现的次数相同——只是一些字符串罢了。有递推式f[i] = f[i-1]*10 + 10^i
,其中f[i-1]*10
是低i位中某数码的出现次数(用0~9共10个数码作为最高位),10^i
是它在最高位的出现次数。
位数少于x的数,枚举1~9作为最高位。最高位中每个数码出现10^i
次,低i位中每个数码出现f[i-1]*9
次。
和x有公共前缀的数,自由的非公共部分每个数码出现f[i-1]
次,公共部分和非自由非公共部分一起暴力统计。公共部分可以每次计算,也可以像我的代码这样放在一起考虑,如x=1234,则1在公共部分出现234次,2在公共部分出现34次,3在公共部分出现4次。
于是又写了一个版本。
#include <cstdio>#include <cstring>using namespace std;const int MAX_N = 13;typedef long long ll;// f[i][j][k]: 以j打头的(i+1)位十进制串含多少个k// g[i][j] = Sigma(f[i][*][j])ll p[MAX_N], f[MAX_N][10][10], g[MAX_N][10], v[2][10];void cal(ll x, ll a[10]){ ll b[MAX_N]; int n = 0; for (ll y = x; y; y /= 10) b[n++] = y % 10; for (int i = 0; i < n-1; ++i) for (int j = 0; j < 10; ++j) a[j] += g[i][j] - f[i][0][j]; for (int i = n-1; i >= 0; --i) for (int j = (i == n-1); j < b[i]; ++j) for (int k = 0; k < 10; ++k) a[k] += f[i][j][k]; for (ll i = 1, y = b[0]; i < n; y = y + b[i]*p[i], ++i) a[b[i]] += y;}int main(){ ll a, b; scanf("%lld %lld", &a, &b); for (int i = 0; i < 10; ++i) f[0][i][i] = g[0][i] = 1; p[0] = 1; for (int i = 1; i < MAX_N; ++i) { p[i] = p[i-1]*10; for (int j = 0; j < 10; ++j) { f[i][j][j] = p[i]; for (int k = 0; k < 10; ++k) { f[i][j][k] += g[i-1][k]; g[i][k] += f[i][j][k]; } } } cal(b+1, v[0]); cal(a, v[1]); for (int i = 0; i < 10; ++i) printf("%lld%c", v[0][i]-v[1][i], " \n"[i == 9]); return 0;}
#include <cstdio>using namespace std;typedef long long ll;const int MAX_N = 13;ll f[MAX_N], p[MAX_N], v[2][10];void cal(ll x, ll a[10]){ ll b[MAX_N]; int n = 0; for (ll y = x; y; y /= 10) b[n++] = y % 10; for (int i = 0; i < n-1; ++i) for (int j = 0; j < 10; ++j) a[j] += (j ? p[i] : 0) + (i ? f[i-1]*9 : 0); // 最高位,低i位 for (int i = n-1, c; c = 0, i >= 0; --i) { for (int j = (i==n-1); j < b[i]; ++c, ++j) a[j] += p[i]; for (int j = 0; j < 10; ++j) a[j] += i ? c*f[i-1] : 0; } for (ll i = 1, y = b[0]; i < n; y += p[i]*b[i], ++i) a[b[i]] += y;}int main(){ ll a, b; scanf("%lld %lld", &a, &b); p[0] = f[0] = 1; for (int i = 1; i < MAX_N; ++i) { p[i] = p[i-1]*10; f[i] = f[i-1]*10 + p[i]; } cal(b+1, v[0]); cal(a, v[1]); for (int i = 0; i < 10; ++i) printf("%lld%c", v[0][i] - v[1][i], " \n"[i == 9]); return 0;}
0 0
- BZOJ 1833 ZJOI2010 count 数字计数 数位DP
- BZOJ 1833 [ZJOI2010]count 数字计数(数位dp)
- 【BZOJ 1833】 [ZJOI2010]count 数字计数|数位DP
- bzoj 1833: [ZJOI2010]count 数字计数(数位dp)
- [bzoj 1833] [ZJOI2010]count 数字计数:数位DP
- BZOJ-1833 [ZJOI2010]count 数字计数 数位DP
- bzoj 1833 [ZJOI2010]count 数字计数 数位dp
- 1833: [ZJOI2010]count 数字计数 数位dp
- 【BZOJ】【P1833】【ZJOI2010】【count 数字计数】【题解】【数位DP】
- bzoj1833: [ZJOI2010]count 数字计数 数位dp
- [BZOJ1833] [ZJOI2010]count 数字计数 && 数位DP
- 【bzoj1833】[ZJOI2010]count 数字计数 数位DP
- Bzoj1833:[ZJOI2010]count 数字计数:数位dp
- bzoj1833[ZJOI2010]count 数字计数 数位DP
- 【bzoj 1833】【codevs 1359】 [ZJOI2010]count 数字计数(数位dp)
- BZOJ 1833: [ZJOI2010]count 数字计数 数位DP,处理前导0
- bzoj 1833 count 数字计数 数位dp
- BZOJ 1833 count 数字计数 数位DP
- CNN卷积神经网络推导和实现
- 【图像算法OpenCV】几何不变矩--Hu矩
- 表单验证常用正则表达
- js调用iframe的方法或属性的问题
- [生存志] 第21节 历代大事件概览 唐朝
- [bzoj 1833] [ZJOI2010]count 数字计数:数位DP
- 258. Add Digits
- linux内核工程导论-Linux用户和权限系统
- uva1388 Graveyard
- 关于sdk4.8.1变异mysql驱动及本地加载mysql数据库
- js--事件--事件循环
- Ubuntu下jdk的安装
- ucloud的CDN > UCDN介绍
- Shell 文件包含