Processing math: 100%

LUOGU P3413 SAC#1 - 萌数(数位dp)

传送门

解题思路

  首先这道题如果有两个以上长度的回文串,那么就一定有三个或两个的回文串,所以只需要记录一下上一位和上上位填的数字就行了。数位dp,用记忆化搜索来实现。设f[i][j][k][0/1]表示填到了第i位,上上位数字为j,上一位数字为k0/1表示有没有出现过回文串的方案数。dfs里在套路的传一个这一位有没有限制和前导0,细节还是比较多的。

代码

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;
const int MAXN = 1005;
const int MOD = 1e9+7;
typedef long long LL;

string l,r;
int cnt,num[MAXN];
LL f[MAXN][15][15][2];

LL dfs(int x,int pre,int pree,bool lim,bool zero,int exist){
	if(x==0) return exist;
	int Max=lim?num[x]:9,p;LL sum=0;
	if(f[x][pre][pree][exist]!=-1 && !lim && !zero) return f[x][pre][pree][exist];
	for(int i=0;i<=Max;i++){
		p=(zero&&i==0)?-1:i;
		int A=pre,B=pree;
		sum+=dfs(x-1,pree,p,(lim&&(p==num[x])),(p==-1),exist|(p!=-1 && (pree==p || pre==p)));		
		sum%=MOD;
	}
	if(!zero && !lim) f[x][pre][pree][exist]=sum;
	return sum;
}

LL solve(string s,bool sub){
	cnt=s.length();
	for(int i=1;i<=cnt;i++)
		num[cnt-i+1]=s[i-1]-'0';
	if(sub){
		int now=1;
		while(num[now]==0) num[now++]=9;
		num[now]--;
		while(!num[cnt] && cnt) cnt--;
	}
	memset(f,-1,sizeof(f));
	return dfs(cnt,-1,-1,1,1,0);
}

int main(){
	cin>>l>>r;
	printf("%lld",((solve(r,0)-solve(l,1))%MOD+MOD)%MOD);
	return 0;
}
posted @   Monster_Qi  阅读(290)  评论(0编辑  收藏  举报
编辑推荐:
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
阅读排行:
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· 程序员常用高效实用工具推荐,办公效率提升利器!
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 【译】WinForms:分析一下(我用 Visual Basic 写的)
点击右上角即可分享
微信分享提示