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

传送门

解题思路

  首先这道题如果有两个以上长度的回文串,那么就一定有三个或两个的回文串,所以只需要记录一下上一位和上上位填的数字就行了。数位\(dp\),用记忆化搜索来实现。设\(f[i][j][k][0/1]\)表示填到了第\(i\)位,上上位数字为\(j\),上一位数字为\(k\)\(0/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;
}

转载于:https://www.cnblogs.com/sdfzsyq/p/9813442.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值