题意: 好在在他眼里,并不是所有数都是萌的。只有满足“存在长度至少为2的回文子串”的数是萌的——也就是说,101是萌的,因为101本身就是一个回文数;110是萌的,因为包含回文子串11;但是102不是萌的,1201也不是萌的。现在SOL想知道从l到r的所有整数中有多少个萌数。由于答案可能很大,所以只需要输出答案对1000000007(10^9+7)的余数。
Strategy: 区间查询显然数位dp, 不过这种查询和普通查询不一样, 包含回文串的数字以后的状态也无法确定, 所以想到查补集, 而且不难发现, 当一个数的连续三个数字都不相同,就能保证这个数不是萌数
状态:
d
p
[
i
]
[
j
]
[
k
]
→
搜
到
长
度
为
i
,
上
一
位
为
j
,
上
上
一
位
为
k
的
数
的
非
回
文
数
的
个
数
dp[i][j][k]\to搜到长度为i, 上一位为j, 上上一位为k的数的非回文数的个数
d p [ i ] [ j ] [ k ] → 搜 到 长 度 为 i , 上 一 位 为 j , 上 上 一 位 为 k 的 数 的 非 回 文 数 的 个 数
目标:
s
u
m
r
−
s
u
m
l
−
(
s
u
m
[
r
]
−
s
u
m
[
l
−
1
]
)
+
1
(
s
u
m
[
i
]
代
表
1
i
内
的
所
有
合
法
数
的
个
数
)
sumr - suml - (sum[r]-sum[l-1]) + 1(sum[i]代表1~i内的所有合法数的个数)
s u m r − s u m l − ( s u m [ r ] − s u m [ l − 1 ] ) + 1 ( s u m [ i ] 代 表 1 i 内 的 所 有 合 法 数 的 个 数 )
边界: 没有
合法判断: 条件转移合法判断
记忆化转移无需预处理
attention: dfs内对下一决策的选择要满足前导零的情况必须是last:-1 且llst:-1, 由于数非常大, 为了避免写高精我们直接把数存到a数组里面去, 并且特判一下l的情况, 注意不要遗漏任何细节
双倍经验: 记忆化细节少
@author: jasonleft 记忆化数位
#include <bits/stdc++.h>
#include <bits/extc++.h>
#define _rep(i, a, b) for (ll i = (a); i <= (b); ++i)
#define _rev(i, a, b) for (ll i = (a); i >= (b); --i)
#define _for(i, a, b) for (ll i = (a); i < (b); ++i)
#define _rof(i, a, b) for (ll i = (a); i > (b); --i)
#define ll long long
#define db double
#define oo 0x3f3f3f3f
#define eps 0.00001
#define all(x) x.begin(), x.end()
#define met(a, b) memset(a, b, sizeof(a))
#define what_is(x) cerr << #x << " is " << x << endl
#define lowbit(x) x &(-x)
const ll maxn = 1e3 + 10 ;
const ll mod = 1e9 + 7 ;
using namespace std;
string l, r;
ll dp[ maxn] [ 10 ] [ 10 ] , cnt, a[ maxn] ;
ll dfs ( ll cur, ll last, ll llst, bool lim, bool zeros)
{
if ( cur == 0 )
return 1 ;
ll & t = dp[ cur] [ last] [ llst] ;
if ( ~ t && ! lim && ! zeros && ~ last && ~ llst)
return t;
int ret = 0 ;
_rep ( i, 0 , 9 )
{
if ( ( zeros || ( i != llst && i != last) ) && ( ! lim || i <= a[ cur] ) )
ret + = dfs ( cur - 1 , ( zeros && i == 0 ? - 1 : i) , ( zeros && i == 0 ? - 1 : last) , lim && i == a[ cur] , zeros && i == 0 ) , ret % = mod;
}
if ( ! lim && ! zeros && ~ last && ~ llst)
t = ret;
return ret;
}
ll _solve ( )
{
cnt = 0 ;
met ( dp, - 1 ) ;
met ( a, 0 ) ;
ll sumr = 0 , suml = 0 ;
cnt = r. size ( ) ;
_for ( i, 0 , cnt)
{
sumr = ( sumr * 10 + r[ i] - '0' ) % mod;
}
reverse ( r. begin ( ) , r. end ( ) ) ;
_for ( i, 0 , r. size ( ) )
a[ i + 1 ] = r[ i] - '0' ;
ll rr = dfs ( cnt, - 1 , - 1 , 1 , 1 ) ;
met ( a, 0 ) ;
cnt = l. size ( ) ;
_for ( i, 0 , cnt)
{
suml = ( suml * 10 + l[ i] - '0' ) % mod;
}
reverse ( l. begin ( ) , l. end ( ) ) ;
_for ( i, 0 , l. size ( ) )
{
a[ i + 1 ] = l[ i] - '0' ;
}
ll llt = dfs ( cnt, - 1 , - 1 , 1 , 1 ) ;
bool diff = 1 ;
_rep ( i, 3 , cnt)
{
if ( ! ( a[ i] != a[ i - 1 ] && a[ i] != a[ i - 2 ] && a[ i - 1 ] != a[ i - 2 ] ) )
{
diff = 0 ;
break ;
}
}
return ( sumr - suml - ( rr - llt) + 1 + + mod + ( diff ? - 1 : 0 ) ) % mod;
}
signed main ( )
{
ios:: sync_with_stdio ( 0 ) ;
cin >> l >> r;
cout << _solve ( ) << endl;
}