DP·数位DP
2015-04-28 17:14
309 查看
题目:
HDU3555
题意:
求区间[1, n]内所有含”49”的数
方法:
数位DP,定义状态:dp
[m]表示第n位(最高位即为第n位)为m的符合要求的数的个数
状态转移:
第n位为m的状态符合要求的数有两种可能:1若m=4,且n-1位为9,1~n-2位为任何数均可以,即有10^(n-2)个,若n-1为不为9,则第n为没有贡献,即以n-1位可能的数为头的所有满足条件的数的总和。2若m!=4,则同m=4的第二种情况
然后求区间[1,n]内有所满足条件的数的个数,即求[1,n+1)内满足条件的数,则以n+1为上界,若一个数有某一位小于n+1同一位上的数,则此数小于n+1(如12345<13345,第4为2<3)。则可以从最高位开始遍历小于n+1的数,以k = n+1 = 7649523(长度为7)为例
从最高位7开始:所有长度为7,且最高位为1~6(小于7)的数均<k,即可在ans上加上
,然后遍历确认最高位为7的数
次高位为6:同理,所有长度为7,最高位确定为7,次高位为1~5(小于6)的数均<k,即可以在ans上加上
,然后遍历确认前两位为76的数
第三位为4:同上,ans加上
,然后前三位为764
第四位为9:同上,ans加上
,然后前三位为7649
此时,确认的位数里面包含了”49”,即之后的位数无论是什么均符合要求,即在ans上加上余下的数(0~523共524个数)即可
测试数据:
2
5000
50000
答案:
199
2475
HDU3555
题意:
求区间[1, n]内所有含”49”的数
方法:
数位DP,定义状态:dp
[m]表示第n位(最高位即为第n位)为m的符合要求的数的个数
状态转移:
第n位为m的状态符合要求的数有两种可能:1若m=4,且n-1位为9,1~n-2位为任何数均可以,即有10^(n-2)个,若n-1为不为9,则第n为没有贡献,即以n-1位可能的数为头的所有满足条件的数的总和。2若m!=4,则同m=4的第二种情况
然后求区间[1,n]内有所满足条件的数的个数,即求[1,n+1)内满足条件的数,则以n+1为上界,若一个数有某一位小于n+1同一位上的数,则此数小于n+1(如12345<13345,第4为2<3)。则可以从最高位开始遍历小于n+1的数,以k = n+1 = 7649523(长度为7)为例
从最高位7开始:所有长度为7,且最高位为1~6(小于7)的数均<k,即可在ans上加上
,然后遍历确认最高位为7的数
次高位为6:同理,所有长度为7,最高位确定为7,次高位为1~5(小于6)的数均<k,即可以在ans上加上
,然后遍历确认前两位为76的数
第三位为4:同上,ans加上
,然后前三位为764
第四位为9:同上,ans加上
,然后前三位为7649
此时,确认的位数里面包含了”49”,即之后的位数无论是什么均符合要求,即在ans上加上余下的数(0~523共524个数)即可
测试数据:
2
5000
50000
答案:
199
2475
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; typedef __int64 ll; ll dp[100][10] = {0}; ll myPow(int a, int b) { ll ans = 1; while ( b-- ) ans *= a; return ans; } ll getAns(ll x) { ll ans = 0; int k = 0; ll m = 1; while ( m < x ) k++, m *= 10; m /= 10; int p = 0; while ( m ) { int c = x / m; for (int i = 0; i != c ; i++){ ans += dp[k][i]; } if ( p == 4 && c == 9 ) { ans += x % m; break; } x %= m; m /= 10; k--; p = c; } return ans; } int main() { ll sumP = 0; for (int i = 2; i != 20 ; i++){ ll sumC = 0; for (int j = 0; j != 10 ; j++){ if ( j == 4 ) dp[i][j] = sumP + myPow(10, i - 2) - dp[i-1][9]; else dp[i][j] = sumP; sumC += dp[i][j]; //printf("%lld ", dp[i][j]); } sumP = sumC; //printf("\n"); } // int num = 1; // for (int i = 400000; i != 500010 ; i++){ // if ( getAns(i) - getAns(i-1) == 1 ) printf("%d:%d\n", num++, i-1); // } int T; scanf("%d", &T); while ( T-- ) { ll n; scanf("%I64d", &n); printf("%I64d\n", getAns(n+1)); } return 0; }
相关文章推荐
- DP·数位DP(3)
- DP·数位DP(2)
- DP·数位DP(5)
- HDU 2089 不要62(数位DP·记忆化搜索)
- HDU 2089 不要62(数位DP·记忆化搜索)
- DP·数位DP(4)
- poj 2282 The Counting Problem && poj 3286 How many 0's? (数位dp)
- hihoCoder 1044 状态压缩·一 (状压dp)
- 拓扑排序&关键路径&数位dp
- HDU 2089 不要62 & HDU 3652 B-number(初级数位DP)
- 多校第6场 HDU 3893&&JLU Drawing Pictures(数位DP变形,矩阵连乘)
- HDU 4352 XHXJ's LIS 数位dp
- HDU 5898&&2016 ACM/ICPC Asia Regional Shenyang Online/ odd-even number [数位DP]【动态规划】
- XHXJ's LIS HDU4352(数位DP)
- HDU - 4507 吉哥系列故事——恨7不成妻 (数位DP&记忆化dfs)好题
- HDU 3652 B-number(数位dp&记忆化搜索)
- hdu 4352 XHXJ's LIS(LIS+数位DP,5级)
- URAL1353---Milliard Vasya's Function(简单数位dp)
- [Codeforces 258B & 259 D]Little Elephant and Elections 数位dp+dfs
- HDU 1024 Max Sum Plus Plus (DP·滚动数组)