Luogu P3413 SAC#1 - 萌数 题解

Describe

题目链接

定义“萌数”: 存在长度至少为$2$的回文子串。

问$[L,R]$中共有多少个萌数字?

对于$100\%$的数据$0\leq L\leq R \leq {10}^{1000}$。

Solution

数位$dp$裸题。

$$DFS(x,las,lasqr,has,lim,st)$$

分别表示第$x$位,上一个数字是$las$,再上一个数字是$lasqr$,是否到达上限$lim$,是否前导$0$。

萌数一定是形如$11$或$101$式的,所以只要判断$las==ilasqr==i$即可。

注意$L,R$都需要高精

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include<bits/stdc++.h>
#define mod 1000000007
#define int long long
using namespace std;
int a[1010],m,f[1010][11][2][2][2],ans1,ans2;
inline int DFS(int x,int las,int lasqr,int has,int lim,int st){//分别表示第$x$位,上一个数字是$las$,再上一个数字是$lasqr$,是否到达上限$lim$,是否前导$0$。
if(x<=0) return has;//结束
if(~f[x][las][has][lim][st]) return f[x][las][has][lim][st];//记忆化
int Max=lim?a[x]:9,res=0;
for(int i=0;i<=Max;i++)
res+=DFS(x-1,i,st?-1:las,has(!st&&i==las)(!st&&i==lasqr),lim&&(i==Max),st&&(i==0))%mod,res%=mod;//注意前导0
if(!st&&~lasqr) f[x][las][has][lim][st]=res;//记忆化
return res;
}
inline int solve(){
if(m<=1) return 0;
for(int i=1;i<=m/2;i++) swap(a[i],a[m-i+1]);//读入的时候是反的
memset(f,-1,sizeof(f));
return DFS(m,-1,-1,0,1,1);
}
signed main(){
char ch=getchar();while(ch<'0'ch>'9') ch=getchar();
m=0;while(ch>='0'&&ch<='9') a[++m]=ch-'0',ch=getchar();
a[m]--;int j=m;while(a[j]==-1) a[j-1]--,a[j]+=10,j--;//L需要-1
ans1=solve();
while(ch<'0'ch>'9') ch=getchar();
m=0;while(ch>='0'&&ch<='9') a[++m]=ch-'0',ch=getchar();
ans2=solve();
printf("%lld\n",(ans2-ans1+mod)%mod);//别忘记%%%
}