之前稍微看过一点数位dp, 也没怎么练习, 现在鸽了这么久差不多全忘了.
今天一个小学弟跑来问我一个很水的题
多个输入, 每次一个正整数 n, 问 [1, n] 范围内有多少个回文数
题目没有明说 n 的范围, 我下意识就回顾了一下以前做这种题用的很傻逼的方法
预处理生成范围内所有的回文数, 排序再对每一个输入进行二分, 返回下标
这个做法真的太傻逼了= =
还好看过数位dp, 可以远离这种暴力流.
回顾一下数位dp入门题 hdu2089
不要62
Problem Description
杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer)。
杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众。
不吉利的数字为所有含有4或62的号码。例如:
62315 73418 88914
都属于不吉利号码。但是,61152虽然含有6和2,但不是62连号,所以不属于不吉利数字之列。
你的任务是,对于每次给出的一个牌照区间号,推断出交管局今次又要实际上给多少辆新的士车上牌照了。Input
输入的都是整数对n、m(0<n≤m<1000000),如果遇到都是0的整数对,则输入结束。
Output
对于每个整数对,输出一个不含有不吉利数字的统计个数,该数值占一行位置。
Sample Input
1 100
0 0Sample Output
80
当时照着模板打的代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
long long DDP[20][2];
int TN[20];
long long DigtialDFS(int pos, int pre, int sta, bool lead, bool limit){
if(pos == -1) return 1;
if(!lead && !limit && DDP[pos][sta] != -1) return DDP[pos][sta];
int up = limit ? TN[pos] : 9;
long long res = 0;
for(int i = 0; i <= up; i++){
if(i == 4 || (pre == 6 && i == 2)) continue;
res += DigtialDFS(pos - 1, i, i == 6, lead && i == 0, limit && i == TN[pos]);
}
if(!limit) DDP[pos][sta] = res;
return res;
}
long long DigtialDP(int x){
int pos = 0;
while(x) TN[pos++] = x % 10, x /= 10;
return DigtialDFS(pos - 1, -1, 0, true, true);
}
int main()
{
int n, m;
memset(DDP, -1LL, sizeof(DDP));
while(scanf("%d%d", &n, &m) != EOF && (n || m)) printf("%I64d\n", DigtialDP(m) - DigtialDP(n - 1));
return 0;
}
一会儿再补注释和思路
#include <stdio.h>
#include <string.h>
int DDP[9][9][2];
int TN[20];
int DigtialDFS(int len, int pos, int sta, int limit){
int i, up, res = 0;
if(pos == -1) return sta;
if(!limit && DDP[len][pos][sta] != -1) return DDP[len][pos][sta];
up = limit ? TN[pos] : 9;
for(i = 0; i <= up; i++){
if(pos == len && i == 0) res += DigtialDFS(len - 1, pos - 1, sta, limit && i == up);
else if(sta && pos < (len + 1) / 2) res += DigtialDFS(len, pos - 1, i == TN[len - pos], limit && i == up);
else res += DigtialDFS(len, pos - 1, sta, limit && i == up);
}
if(!limit) DDP[len][pos][sta] = res;
return res;
}
int DigtialDP(int x){
int pos = 0;
while(x) TN[pos++] = x % 10, x /= 10;
return DigtialDFS(pos - 1, pos - 1, 1, 1);
}
int main()
{
int n;
memset(DDP, -1, sizeof(DDP));
while(scanf("%d", &n) != EOF && n) printf("%d\n", DigtialDP(n) - 1);
return 0;
}