回文串+数位dp 萌数

link

大意:
求区间 [L,R] 中有长度大于 2 的回文子串的数量。 数据范围:1≤L<R≤10^1000

思路:
对于这种回文串的东西第一眼肯定是想到合并状态。如果正着想的话,显然所有回文串都满足有相邻两位相等或者间隔一位的两个数字相等,但是这样计数的话还要考虑到相等的位置以及第二种情况时中间数字与两边数字是否相等等一系列情况,想想也不是1e1000能解决的

所以可以反过来考虑,那就是统计不含回文字串的个数,不难发现其性质就是每一位都与前两位不同。所以设一个三维的dp,i表示当前位数,j表示前一位,k表示前一位的前一位。做数位dp的话,转移就按照正常的转移来就好了,只是中间遍历时要特判一下前导0时的情况,需要将前两位都置为-1。

最后高精度减法用取模运算来代替即可

思路不是很难,但是写起来还是有些磕磕绊绊的,还是太生了

code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
const ll N=1e5+10;
const ll mod=1e9+7;
string n,m;
ll dp[1010][15][15];
ll a[1010];
ll cnt=0;
ll gt(string s)
{
	ll ans=0;
	for(int i=0;i<s.size();++i)
	{
		ans=(ans*10%mod+(s[i]-'0'))%mod;
	}
	return ans;
}
ll dfs(ll x,ll head,ll op,ll pre,ll ppre)//head 前导0,op 上限 
{
	if(x==0) return 1;
	if(!head&&!op&&dp[x][pre][ppre]!=-1&&pre!=-1&&ppre!=-1) return dp[x][pre][ppre];
	ll tot=0;
	ll lim=op?a[x]:9;
	for(int i=0;i<=lim;++i)
	{
		if(i==pre||i==ppre) continue;
		if(head&&i==0) tot=(tot+dfs(x-1,1,op&&i==lim,-1,-1))%mod;
//		else if(head) tot=(tot+dfs(x-1,0,op&&i==lim,-1,i))%mod;
		else tot=(tot+dfs(x-1,0,op&&i==lim,i,pre))%mod;
	}
	if(!head&&!op&&pre!=-1&&ppre!=-1) dp[x][pre][ppre]=tot;
	return tot;
}
ll f(string s,ll opp)
{
	memset(dp,-1,sizeof dp);
	cnt=0;
	for(int i=s.size()-1;i>=0;--i) a[++cnt]=s[i]-'0';
	if(opp==1)
	{
		a[1]--;
		for(int i=1;i<=cnt;++i)
		{
			if(a[i]==-1)
			{
				a[i]=9;
				a[i+1]--;
			}
		}
	}
//	for(int i=1;i<=cnt;++i) cout<<a[i];
//	cout<<endl;
	return dfs(cnt,1,1,-1,-1);
}
void solve()
{
	cin>>n>>m;
	ll nn=0,mm=0;
	ll all=((gt(m)-gt(n)+1)%mod+mod)%mod;
	ll det=((f(m,0)-f(n,1))%mod+mod)%mod;
//	cout<<det<<endl;
	cout<<(((all-det)%mod)+mod)%mod<<endl;
}
int main()
{
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	solve();
	return 0;
}

双倍经验:[BalticOI 2013 Day1] Palindrome-Free Numbers

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值