Strategy: 区间查询显然数位dp, 我先设计dp[i][j]代表搜到第i位, 上一位数字是j所能得到的方案数, 然而, dp[i][j]状态有重复的(难道所有问题的解只有13*13吗), 然后改为状态
d
p
[
i
]
[
j
]
[
k
]
[
m
]
→
搜
到
第
i
位
,
上
一
位
尾
j
,
目
前
余
数
为
k
,
是
否
出
现
过
′
1
3
′
,
这
样
搜
索
的
状
态
显
然
是
唯
一
的
dp[i][j][k][m]\to搜到第i位,上一位尾j,目前余数为k,是否出现过'13', 这样搜索的状态显然是唯一的
dp[i][j][k][m]→搜到第i位,上一位尾j,目前余数为k,是否出现过′13′,这样搜索的状态显然是唯一的
状态: 同上
目标:
(
s
u
m
[
r
]
)
(
s
u
m
[
i
]
代
表
1
i
内
的
所
有
合
法
数
的
个
数
)
(sum[r])(sum[i]代表1~i内的所有合法数的个数)
(sum[r])(sum[i]代表1i内的所有合法数的个数)
边界: 没有
合法判断: 条件转移合法判断
记忆化转移无需预处理
attention: 状态的唯一性
双倍经验: 记忆化细节少
@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 id(x) ((x + 8))#define bin(x) cerr << #x << " is " << bitset<8>(x) << endl#define what_is(x) cerr << #x << " is " << x << endl#define lowbit(x) x &(-x)usingnamespace std;const ll maxn =14;const ll mod =9999973;
ll dp[maxn][maxn][maxn][2], cnt, a[maxn], r;
ll dfs(ll cur, ll last,bool lim,bool zeros, ll num,bool have){if(cur ==0){return have && num %13==0;}
ll& t = dp[cur][last][num][have];if(~t &&!lim &&!zeros)return t;
ll ans =0;_rep(i,0,9){if(!lim || i <= a[cur]){
ans +=dfs(cur -1,(zeros && i ==0?-1: i), lim && i == a[cur], zeros && i ==0,(num *10+ i)%13, have ||(last ==1&& i ==3));}}if(!lim &&!zeros) t = ans;return ans;}
ll __ask(ll __){met(a,0);
cnt =0;while(__)
a[++cnt]= __ %10, __ /=10;returndfs(cnt,-1,1,1,0,0);}signedmain(){
ios::sync_with_stdio(0);met(dp,-1);while(cin >> r){
cout <<__ask(r)<< endl;}}