Let life be beautiful l|

Ginger_he

园龄:3年1个月粉丝:5关注:5

洛谷P6754题解

本文同步更新于洛谷博客

题目描述

给定 a,b,求区间 [a,b] 中有多少个不含长度大于一的回文子串的数字串。

题解

还是比较套路的数位 dp。我们传五个参数 k,x,y,p,q 进入 dfs,分别表示枚举到第 k 位,前两位为 x,前一位为 y,是否为前导 0,以及这一位填的数有没有限制,用 f 数组记忆化即可。
下面来简要说明一下如何判断非回文串。不妨设回文串为 s1s2...sn,接下来进行分类讨论:若 n 为奇数,令 m=n+12,则 sm1smsm+1 必为回文串;若 n 为偶数,令 m=n2,则 smsm+1 必为回文串。因此我们在填到第 x 位时,只需要判断它与第 x1 位和第 x2 位是否相等即可。

注意

我们把填前导 0 的位置设为 1,这样会更加方便,但是 xy1 的时候不能进行记忆化。

Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int len,a[20];
ll l,r,f[20][10][10];
ll dfs(int k,int x,int y,int p,int q)
{
    if(!k)
        return 1;
    if(!p&&!q&&x!=-1&&y!=-1&&f[k][x][y]!=-1)
	return f[k][x][y];
    int z=q?a[k]:9;
    ll res=0;
    for(int i=0;i<=z;i++)
    {
	if(i==x||i==y)
	    continue;
	res+=dfs(k-1,y,(p&&!i)?-1:i,p&&!i,q&&(i==z));
    }
    if(!p&&!q&&x!=-1&&y!=-1)
        f[k][x][y]=res;
    return res;
}
ll divide(ll x)
{
    len=0;
    while(x)
    {
        a[++len]=x%10;
	x/=10;
    }
    return dfs(len,-1,-1,1,1);
}
int main()
{
    memset(f,-1,sizeof(f));
    scanf("%lld%lld",&l,&r);
    printf("%lld\n",divide(r)-divide(l-1));
    return 0;
}

本文作者:Ginger_he

本文链接:https://www.cnblogs.com/Gingerhe/p/15837884.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Ginger_he  阅读(131)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起