10数位DP:数字计数
[ZJOI2010] 数字计数
题目描述
给定两个正整数 a 和 b,求在 [a,b] 中的所有整数中,每个数码(digit)各出现了多少次。
输入格式
仅包含一行两个整数 a,b,含义如上所述。
输出格式
包含一行十个整数,分别表示 0∼9 在 [a,b] 中出现了多少次。
样例 #1
样例输入 #1
样例输出 #1
1
| 9 20 20 20 20 20 20 20 20 20
|
提示
数据规模与约定
- 对于 30% 的数据,保证 a≤b≤106;
- 对于 100% 的数据,保证 1≤a≤b≤1012。
数位DP主要通过记忆化搜索实现,记忆化搜索的本质就是把条件对应的结论记下来,相同条件一定最后对应相同的结论,条件的个数也就决定了DP的维数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| #include <bits/stdc++.h> #define int long long using namespace std; int ay[20];
int dp[20][2][20][2];
int dfs(int pos,int limit,int sum,int zero,int target) { int ret=0; if(pos==0)return sum; if(dp[pos][limit][sum][zero]!=-1)return dp[pos][limit][sum][zero]; int maxnum=limit?ay[pos]:9;
for(int i=0;i<=maxnum;i++) { ret+=dfs(pos-1,limit &&(i==maxnum),sum+((i==target) && (i||!zero)),zero && (i==0),target);
} dp[pos][limit][sum][zero]=ret; return ret; } int part(int a,int d) { int len=0; while(a) { ay[++len]=a%10; a/=10; } memset(dp, -1, sizeof dp); dfs(len,1,0,1,d);
} signed main() { int a,b; cin>>a>>b; for(int i=0;i<=9;i++) { cout<<part(b,i)-part(a-1,i)<<" "; }
return 0; }
|
再来看一道题:
[SCOI2009] windy 数
题目背景
windy 定义了一种 windy 数。
题目描述
不含前导零且相邻两个数字之差至少为 2 的正整数被称为 windy 数。windy 想知道,在 a 和 b 之间,包括 a 和 b ,总共有多少个 windy 数?
输入格式
输入只有一行两个整数,分别表示 a 和 b。
输出格式
输出一行一个整数表示答案。
样例 #1
样例输入 #1
样例输出 #1
样例 #2
样例输入 #2
样例输出 #2
提示
数据规模与约定
对于全部的测试点,保证 1≤a≤b≤2×109。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| #include <bits/stdc++.h> using namespace std; int ay[100]; int len=0; int dp[100][100];
int dfs(int pos,int prenum,int st,int limit) { if(pos>len)return 1; if(limit==0 && dp[pos][prenum]!=-1)return dp[pos][prenum]; int maxnum=limit?ay[len+1-pos]:9; int ret=0; for(int i=0;i<=maxnum;i++) { if(abs(i-prenum)<2)continue; if(i==0 && st==1)ret+=dfs(pos+1,-2,st,limit && (i==maxnum)); else ret+=dfs(pos+1,i,0,limit && (i==maxnum)); } if(limit==0 && st==0)dp[pos][prenum]=ret;
return ret; } int part(int a) { len=0; while(a) { ay[++len]=a%10; a/=10; } memset(dp, -1, sizeof (dp)); return dfs(1,-2,1,1); } int main() { int a,b; cin>>a>>b; cout<<part(b)-part(a-1)<<endl;
return 0; }
|
咱就主打一个看注释吧。
Harbin Institute of Technology, Shenzhen 计算机科学与技术 本科在读