题解

xy0313 2020-09-28 20:42:20 2020-09-30 9:11:51

这是学完数位DP的第三天打的,第一次见这个题,慌慌张张十分钟打完了代码,结果居然一遍过了,写篇题解纪念一下

=============手动分割线=====================

数位DP是有套路的,我学的yxc的,可以去acwing上看看他数位DP题的视频讲解

(这其实就是个数位D模板题)

#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;
}

看懂了记得跟一下贴 >-<

看懂了记得跟一下贴 >-<

看懂了记得跟一下贴 >-<

共 1 条回复

liuzhenchao

tql