1 条题解
-
0
自动搬运
来自洛谷,原作者为

zjh114514
逸一时,误一世!搬运于
2025-08-24 21:15:41,当前版本为作者最后更新于2023-11-13 21:40:16,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
观前提示:本题解建议已经有数位 dp 基础的谷民食用。如果不知道什么是数位 dp,请移步 P2602,那里有非常详细的数位 dp 解析。
求回文数(加强版)题解
题意
给出一个正整数 ,求 中回文数的个数对 取模的值。
思路
观察到 很大,可以考虑数位 dp。
简单思考可以发现,对于不足 位的数,可以提前计算出回文数的个数。
而对于 位的数,可以采用暴力求回文数的做法,枚举回文数的一半得到整个回文数,并用记忆化搜索优化。代码
#include<bits/stdc++.h> using namespace std; const int MAXN=105,MOD=20091119; char s[MAXN]; int a[MAXN],len; int dp[2][MAXN]; int temp[MAXN],total; int check(){ for(int i=total,j=(len>>1)+(len&1);i&&j;i--,j--){//+(len&1)判断奇/偶回文数。 if(temp[i]>a[j]) return 0; if(temp[i]<a[j]) return 1; } return 1; } int dfs(bool lim,int pos){//lim为1时代表前面高位的都和原数一样,pos为当前下标。 if(pos==(len>>1)){//枚举到一半。 if(!lim) return 1;//如果lim为0,后面可以随便取,返回1。 return check();//否则判断一下是否超出原数,仅会判断1次。 } if(~dp[lim][pos]) return dp[lim][pos]; int res=0; for(int i=0;i<=9;i++){ if(pos==len&&!i) continue;//最高位必不等0。 if(lim&&i>a[pos]) break;//超出原数就终止循环。 temp[++total]=i;//存下回文数的一半。 res=(res+dfs(lim&&i==a[pos],pos-1))%MOD; total--; } return dp[lim][pos]=res; } int solve(){ for(int i=1;i<=len;i++) a[i]=s[len-i+1]-48;//转成数字,a[1]为个位。 int res=0; for(int i=len-1;i;i--){ int res2=9;//避免前导零。 for(int j=i-1;j>(i>>1);j--) res2=(res2*10)%MOD; res=(res+res2)%MOD; } //提前计算不足n位的数的回文数个数。 memset(dp,-1,sizeof(dp)); res=(res+dfs(1,len))%MOD; return res; } int main(){ scanf("%s",s+1); len=strlen(s+1); printf("%d",solve()); return 0; }
- 1
信息
- ID
- 9165
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者