这是学完数位DP的第三天打的,第一次见这个题,慌慌张张十分钟打完了代码,结果居然一遍过了,写篇题解纪念一下
=============手动分割线=====================
数位DP是有套路的,我学的yxc的,可以去看看他数位DP题的视频讲解
#include <iostream>
using namespace std;
const int N = 10;
int f[N][N];//f[i][j] 表示 我们填到第i位,当第i位填j的时候有多少种合适的车牌
void init()//数位DP日常初始化
{
for(int i = 0;i <= 9;i ++) f[1][i] = 1; //日常水掉第一位
f[1][4] = 0; //显然
for(int i = 2;i <= N;i ++) //从第2位开始填
for(int j = 0;j <= 9;j ++) //j表示第i位我想要拿着j去看看能不能填
for(int k = 0;k <= 9;k ++)//k表示第i - 1位我填的什么,i - 1 位是我们之前填好的,所以可以拿来用
{
if(k == 4 || j == 4) continue;
if(j == 6 && k == 2) continue;//如果第i位是6,i - 1位是2肯定是不行的
f[i][j] += f[i - 1][k];//日常状态转移
}
}
int dp(int x)
{
if(!x) return 1; //日常边界判断,有的数位DP题里必须有,这道题需不需要你交一下试试就知道了
int a[12] = {0}; //我要用a数组把这个数的每一位都取出来
int l = 0;
int ans = 0;
int last = 0; //last用来看上一位是不是6,如果是6 那么这一位我就不能填2了
while(x)
{
a[++ l] = x % 10;
x /= 10;
}
for(int i = l;i >= 1;i --)
{
for(int j = 0;j < a[i];j ++) //因为是车牌,所以第一位可以是0,故从0循环
{
if(j == 4) continue;
if(last == 6 && j == 2) continue;
ans += f[i][j];
}
if(a[i] == 4) break;
if(a[i] == 2 && last == 6) break;
last = a[i];
if(i == 1) ans ++; //本来没加这句话,但是写完发现答案少一,于是加上,表示所有的都填完了,传进来的这个x也能填
}
return ans;
}
int main()
{
init();
int l,r;
while(cin >> l >> r,l && r)
{
cout << dp(r) - dp(l - 1) << endl;
}
return 0;
}
看懂给个赞吧 ><
看懂给个赞吧 ><
看懂给个赞吧 >_<
蟹蟹啦
# tql
yzy yyds!(手动狗头)
%%%
没有被线段树恶心,被数位DP恶心到了。