Strategy: 显然数位dp, 又是和取模有关,我原本考虑:
d
p
[
i
]
[
j
]
→
dp[i][j]\to
dp[i][j]→目前搜到第i个数, 且填的数的和是j, 然后dfs终点特判能不能除尽, 结果状态在原数是100+的时候依旧又重复的情况.题解有个神奇的方法, 枚举模数(居然没t). 本题的难点在于,填数的和是在变换的, 所以模数就不确定了,怎么办, 联想到
s
u
m
≤
162
sum\leq162
sum≤162 于是我们就可以在sum的范围内枚举模数 只是复杂度常数*162
状态:
d
p
[
i
]
[
k
]
[
j
]
→
dp[i][k][j]\to
dp[i][k][j]→搜到第i位, 填数和是i, 原数模上模数是j的情况, 这题模数最多只有18*9=162个,
目标:
(
s
u
m
[
r
]
−
s
u
m
[
l
−
1
]
)
(
s
u
m
[
i
]
代
表
1
i
内
的
所
有
合
法
数
的
个
数
)
(sum[r] - sum[l-1])(sum[i]代表1~i内的所有合法数的个数)
(sum[r]−sum[l−1])(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 =170;
ll dp[20][maxn][maxn][2], l, r, a[20], mod, cnt;
ll dfs(ll cur, ll num, ll sum,bool up){if(cur ==0)return sum ==0?0: sum == mod && num ==0?1:0;
ll &t = dp[cur][num][sum][up];if(~t)return t;
t =0;// 不要忘记初始化_rep(i,0,9){if(!up || i <= a[cur])
t +=dfs(cur -1,(num *10+ i)% mod, sum + i, up && i == a[cur]);}return t;}
ll __ask(ll __){met(a,0);
cnt =0;while(__)
a[++cnt]= __ %10, __ /=10;
ll res =0;for(mod =1; mod <= cnt *9; mod++){met(dp,-1);
res +=dfs(cnt,0,0,1);}//what_is(res);return res;}signedmain(){
ios::sync_with_stdio(0);
cin >> l >> r;
cout <<__ask(r)-__ask(l -1)<< endl;}