洛谷 B3883 [信息与未来 2015] 求回文数(加强版)
题意
找出\([1,n]\)回文数字
思路
数位dp
我们在dfs过程中需要知道哪里是回文中点 , 设\(h\)为\(n\)的位数 , 回文中点为\(center\) , 一般而言为\(center = h/2\)
注意\(center\)的值 , 如果是奇数个 , 那么有\(aba\) , \(b可以取值0-9\) , 所以\(center\)为\(h>>1\)才行(好像说了句废话)
但是如果有各种前导零的话 , 那就\(h\)就会随着前导零个数增加而较少 , 进而成为变量
所以可以提前处理出位数小于\(h\)的所有点
回文串的特点在于 ,如果前半段确定 , 那么后半也是确定的
对于没有limit的dfs来说 , 就是 \(1\) , 而对有有\(limit\)的dfs(实际上只有一个) , 单独判断一下就好
这是我见过的第一道不在\(!pos\)时终止的数位dp
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long int
inline int read() {
int ans = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-')f = -1;
ch = getchar();
}
while (ch <= '9' && ch >= '0') {
ans = ans * 10 + ch - '0';
ch = getchar();
}
return ans * f;
}
int a[110];
int cnt = 0;
int f[110];
const int mod = 20091119;
int dfs(int pos,int center,bool limit) {
if (pos == center) {
return !limit;
}
if (!limit && ~f[pos])
return f[pos];
int up = limit?a[pos]:9;
int down = pos==cnt?1:0;
int ans = 0;
for (int i = down; i<= up; i++) {
ans = (ans + dfs(pos-1,center,limit&&i==up)) % mod;
}
if (!limit) f[pos] = ans;
return ans;
}
int qpow(int a,int b) {
int ans = 1;
while (b) {
if (b&1)ans = (ans * a)%mod;
a = (a*a)%mod;
b>>=1;
}
return ans;
}
int work(string x) {
for (auto e : x) {
a[++cnt] = e-'0';
}
int res = 0;
for (int i = 1; i<= cnt-1; i++) {
int mid = i+1>>1;
res = (res + qpow(10,mid) - qpow(10,mid-1)) %mod;
}
reverse(a+1,a+1+cnt);
return (dfs(cnt,cnt>>1,true) + res) % mod;
}
signed main() {
memset(f,-1,sizeof f);
string n;
cin>>n;
int mid = n.size()/2 -1;
string left = string(n.begin(),n.begin() + mid+1);
string right = string((n.size()&1)?n.begin()+mid+2:n.begin()+mid+1,n.end());
reverse(left.begin(),left.end());
int ans = work(n) + (left <= right);
cout<<ans % mod;
return 0;
}

浙公网安备 33010602011771号