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