题目大意:
求区间回文数,区间比较大.
题目思路:
区间大了之后我们自然要想到数位dp解决.
对一个数字,dp它的前 n 2 \frac{n}{2} 2n位。考虑到递归出口时,怎样算合法.
令上界为 X X X,前一半数为 x 1 x_1 x1,后一半数为 x 2 x_2 x2,dp出来的前一半数为: Y Y Y.
1.若前半数位没有顶到上界,则 Y < x 1 Y < x_1 Y<x1,则 Y + r e v e r s e ( Y ) < x 1 + x 2 = X Y+reverse(Y) < x_1+x_2 = X Y+reverse(Y)<x1+x2=X. 一定合法 (+代表拼接).
2.若顶到上界,则 Y = = x 1 Y == x_1 Y==x1,则当 r e v e r s e ( Y ) ≤ x 2 reverse(Y) \leq x_2 reverse(Y)≤x2时才合法.
这样我们 d p dp dp转移的时候除了维护数位,是否顶到上界以外,还需要记录 r e v e r s e ( Y ) reverse(Y) reverse(Y)和 x 2 x_2 x2的大小关系:
每进行到下一个数位,在
Y
Y
Y的尾部增加一个数字,即在
r
e
(
Y
)
re(Y)
re(Y)的顶部增添一个数字
w
w
w。
令之前的大小关系为
s
t
a
sta
sta(=1代表之前的
r
e
(
Y
)
≤
x
2
re(Y)\leq x_2
re(Y)≤x2,=0反之)
考虑状态转移:
当
w
<
X
[
n
−
s
t
e
p
+
1
]
w<X[n-step+1]
w<X[n−step+1]
s
t
a
:
=
1
sta:=1
sta:=1
当
w
=
=
X
[
n
−
s
t
e
p
+
1
]
w==X[n-step+1]
w==X[n−step+1]
s
t
a
sta
sta不变
当
w
>
X
[
n
−
s
t
e
p
+
1
]
w>X[n-step+1]
w>X[n−step+1]
s
t
a
=
0
sta=0
sta=0
递归出口返回 ( ! l i m ) ∣ ∣ s t a (!lim) || sta (!lim)∣∣sta
还有一些细节看代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define vi vector<int>
#define vll vector<ll>
#define fi first
#define se second
const int maxn = 1e6 + 5;
const int mod = 1e9 + 7;
ll a[maxn] , n , s[50] , dp[20][2][2];
string dig;
ll dfs (int step , int lim , int sta , int n){
if (n & 1){
if (step * 2 - 1 > n){
return (!lim) || sta;
}
}else {
if (step * 2 > n){
return (!lim) || sta;
}
}
ll &x = dp[step][lim][sta];
if ( ~x ) return x;
int up , low;
low = (step == 1 ? 1 : 0);
up = (lim ? dig[step] - '0' : 9);
ll ans = 0;
int dm = dig[n - step + 1] - '0';
for (int i = low ; i <= up ; i++){
int nsta;
if (i < dm) nsta = 1;
else if (i == dm) nsta = sta;
else nsta = 0;
ans += dfs(step + 1 , lim && i == up , nsta , n);
}
return x = ans;
}
ll calc (ll x , bool ok){
if (x == -1) return 0;
memset(dp , -1 , sizeof dp);
dig = to_string(x);
n = dig.size();
dig = '#' + dig;
ll ans = 0;
if (ok) ans = s[n - 1];
ans += dfs(1 , true , 1 , n);
if (n == 1) ans++;
return ans;
}
int main()
{
ll base = 0;
for (int i = 1 ; i <= 17 ; i++)
s[i] = s[i - 1] + calc(base = base * 10 + 9 , false);
ios::sync_with_stdio(false);
int t; cin >> t;
int cnt = 0;
while (t--){
ll x , y; cin >> x >> y;
if (x > y) swap(x , y);
cout << "Case " << (++cnt) << ": ";
cout << calc(y , true) - calc(x - 1 , true) << endl;
}
return 0;
}