トピックリンク:https://www.luogu.com.cn/problem/P3413
タイトル効果:
定義手段孟番号:ナンバー会うの「サブ回文文字列2の少なくとも長さが存在します」。
間隔を探している\([L、R] \ ) 出芽の数の範囲の数。
問題解決のアイデア:
の使用デジタルDP、それを解決します。
定義された状態\(F [POS] [P1 ]、[P2] \)は、 スキーム満たし、以下の条件を表します。
- ときに第1のビット期間\(POS \)ビット。
- その数の前にその数の前にある\(P1 \) 。
- その数の前にある(P2 \)\。
あなたはの機能を開くことができますdfs(int pos, int p1, int p2, bool limit)
解決、中に:
- \(POS、P1、P2 \ ) 先に定義しました。
- \(上限は\)電流が制限された状態にあることを示しています。
注:入力文字列の先頭は、次いで、変換入力を開始するように、ビット数は、1000です。
次のようにコードは次のとおりです。
#include <bits/stdc++.h>
using namespace std;
const long long MOD = 1000000007;
long long f[1010][10][10], pow10[1010];
int a[1010];
char ch[1010];
void init() {
memset(f, -1, sizeof(f));
pow10[0] = 1;
for (int i = 1; i <= 1000; i ++) pow10[i] = pow10[i-1] * 10 % MOD;
}
long long dfs(int pos, int p1, int p2, bool limit) {
if (pos < 0) return 0; // 因为我一旦找到回文子串会返回,所有到pos<0时还没有找到就直接返回0了
if (!limit && p1!=-1 && p2!=-1 && f[pos][p1][p2] != -1) return f[pos][p1][p2];
int up = limit ? a[pos] : 9;
long long tmp = 0;
for (int i = 0; i <= up; i ++) {
if (p1 == i || p2 == i) {
if (limit && i==up) {
// tmp += num % pow10[pos] + 1; // 不能这么算,因为是大数
long long t = 0;
for (int j = pos-1; j >= 0; j --)
t = (t * 10 + a[j]) % MOD;
tmp += t + 1;
}
else tmp += pow10[pos] % MOD;
}
else
tmp += dfs(pos-1, p2, (p2==-1&&i==0&&pos>0)?-1:i, limit && i==up);
tmp %= MOD;
}
if (!limit && p1!=-1 && p2!=-1) f[pos][p1][p2] = tmp;
// printf("dfs pos=%d, p1=%d, p2=%d, limit=%d, tmp = %lld\n", pos, p1, p2, limit, tmp);
return tmp;
}
long long get_num(bool minus1) {
cin >> ch;
int len = strlen(ch);
for (int i = 0; i < len; i ++) a[i] = ch[len-1-i] - '0';
// 判断是否为0
bool all0 = true;
for (int i = 0; i < len; i ++) if (a[i] != 0) { all0 = false; break; }
if (all0) return 0;
// 判断是否要减1
if (minus1) {
a[0] --;
for (int i = 0; i < len; i ++) {
if (a[i] < 0) { a[i] += 10; a[i+1] --; }
else break;
}
}
return dfs(len-1, -1, -1, true);
}
int main() {
init();
long long num_l = get_num(true);
long long num_r = get_num(false);
cout << (num_r - num_l + MOD) % MOD << endl;
return 0;
}