洛谷P3413 萌数

https://www.luogu.com.cn/problem/P3413

回文长度2或者3就可以裁定,值得注意的是dp[pos][pre][ppre]可能应对3334321和5554321(都有321),所以要引入最新的变量才行。

dp[pos][pre][ppre][sum],具体套了板子,返回的时候记得让pre和ppre的数字不是前导0

#include<iostream>
#include<queue>
#include<string>
#include<cstring>
using namespace std;
typedef long long ll;
int T, n, m, len, a[2020];
ll l, r, dp[1010][14][13][3];
ll mod = 1e9 + 7;

//                                  记录答案 ppre是1能算
ll dfs(int pos, int pre, int ppre, ll sum, int d, int lead, int limit)
//pos搜到的位置
//pre前一位数
//st当前公差最大差值
//sum整个数字的最大价值
//d共差
//lead判断是否有前导0
//limit判断是否有最高位限制
{
	if (pos > len) return sum;//dp结束
	//记录状态(计划搜索)
	//注意d有负数,最小可以到-9,所以记录时数组下标是d+10
	if ((dp[pos][pre][ppre][sum] != -1 && (!limit) && (!lead)) && d == 1) return dp[pos][pre][ppre][sum] %= mod;
	ll ret = 0;
	int res = limit ? a[len - pos + 1] : 9;//最高位最大值

	for (int i = 0; i <= res; i++)
	{
		//有前导0且这位也是前导0,一切不变只有位数变化
		if ((!i) && lead) {
			ret += dfs(pos + 1, 0, 0, 0, 0, 1, limit && (i == res));
			ret %= mod;
		}

		//有前导0但这位不是前导0(这位是数字的最高位)开始有前一位,一个数形成等差数列
		else if (i&&lead) {//当前位置是最高位
			ret += dfs(pos + 1, i, 0, 0, 0, 0, limit && (i == res));
			ret %= mod;
		}
		else {//前面已经有非0的数字了lead = 0
			ll su = (i == pre)  || (sum == 1);
			if (d == 1 && i == ppre) su = 1;
			ret += dfs(pos + 1, i, pre, su, 1, 0, limit && (i == res));
			ret %= mod;

		}
	}
	ret %= mod;
	//没有前导0和最高限制时可以直接记录当前dp值以便下次搜到同样的情况可以直接使用。
	return (!limit && !lead && d == 1) ? dp[pos][pre][ppre][sum] = ret : ret;
}
int list[2020];


ll cal(string  x,int cl)
{
	len = 0;
	
	for (int i = 0; i < x.length(); i++) {
		list[i] = x[i] - '0';
	}
	list[x.length()-1] -= cl;

	for (int i = x.length() - 1; i >= 0; i--) {
		if (list[i] < 0) {
			list[i] = 9;
			list[i - 1] --;
		}
	}
	int f = 0;
	for (int i = 0; i < x.length(); i++) {
		if (f == 0 && list[i] == 0) list[i] = -1;
		if (list[i] > 0) f = 1;
	}
	
	for (int i = x.length() - 1; i >= 0; i--) {
		if (list[i] == -1) break;
		a[++len] = list[i];
	}
	memset(dp, -1, sizeof dp);
	return dfs(1, 0, 0, 0, 0, 1, 1);//-38是随便赋的其实赋成-10就行了……
}

string sn;

int main()
{
	
	cin >> sn;
	ll ans = cal(sn, 1);
	cin >> sn;
	ll cns = cal(sn, 0); 
	cout << (cns - ans + mod) % mod << endl;
	//l是0的时候要特别注意!
	//printf("%lld
", part(r) - part(l-1));
	
	return 0;
}

  

寻找真正的热爱
原文地址:https://www.cnblogs.com/lesning/p/13646038.html