BZOJ 1799 [Ahoi2009] self 同类分布(数位DP)BZOJ千题计划(quexin
Posted 繁凡さん
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 1799 [Ahoi2009] self 同类分布(数位DP)BZOJ千题计划(quexin相关的知识,希望对你有一定的参考价值。
整理的算法模板合集: ACM模板
实际上是一个全新的精炼模板整合计划
题目链接
https://hydro.ac/d/bzoj/p/1799(样例时限设置有问题,应该为 2 s 2s 2s)
https://www.luogu.com.cn/problem/P4127
题目描述
给出 a , b a,b a,b,求出 [ a , b ] [a,b] [a,b] 中各位数字之和能整除原数的数的个数。
1 ≤ a ≤ b ≤ 1 0 18 1 ≤ a ≤ b ≤ 10^{18} 1≤a≤b≤1018
Solution
显然考虑数位DP。
设 s u m \\mathrm{sum} sum 表示数的各位数值和, s t \\mathrm{st} st 表示当前的数
显然当前的数合法,当且仅当 s t ≡ 0 ( m o d s u m ) \\mathrm{st}\\equiv 0\\pmod {\\mathrm{sum}} st≡0(modsum)
但是这里 s t ≤ 1 0 18 \\mathrm{st}\\le 10^{18} st≤1018,显然无法枚举,题目中有模数 s u m \\mathrm{sum} sum,所以我们这里考虑取模。
但是不同的状态, s u m \\mathrm{sum} sum 是在动态调整的, s u m \\mathrm{sum} sum 很小,我们可以直接枚举 m o d \\mathrm{mod} mod,统计答案的时候判断二者是否相等以及是否满足 s t ≡ 0 ( m o d s u m ) \\mathrm{st}\\equiv 0\\pmod {\\mathrm{sum}} st≡0(modsum) 即可。
实现直接套用记忆化搜索数位DP的模板即可。
模板详见:https://www.luogu.com.cn/blog/virus2017/shuweidp
我们记录位置 p o s \\mathrm{pos} pos ,数值和 s u m \\mathrm{sum} sum,当前的数 s t \\mathrm{st} st,以及限制 l i m i t \\mathrm{limit} limit。
若当前位 l i m i t = 1 \\mathrm{limit}=1 limit=1 而且已经取到了能取到的最高位时,下一位 l i m i t = 1 \\mathrm{limit}=1 limit=1 ; 若当前位
l i m i t = 1 \\mathrm{limit}=1 limit=1 但是没有取到能取到的最高位时,下一位 l i m i t = 0 \\mathrm{limit}=0 limit=0 ; 若当前位
l i m i t = 0 \\mathrm{limit}=0 limit=0 时,下一位 l i m i t = 0 \\mathrm{limit}=0 limit=0 。
Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int maxn = 200 + 7;
int n, m, s, t;
ll ans;
int len, a[20], mod;
ll l, r;
ll f[20][maxn][maxn];
ll dfs(int pos, int sum, ll st, int limit)
{
if(pos > len && sum == 0) return 0;
if(pos > len) return st == 0 && sum == mod ? 1 : 0;
if(limit == 0 && f[pos][sum][st] != -1)
return f[pos][sum][st];
ll res = 0;
int tmp = limit ? a[len - pos + 1] : 9;
for (int i = 0; i <= tmp; ++ i)
res += dfs(pos + 1, sum + i, (st * 10 + i) % mod, i == tmp && limit);
return limit ? res : f[pos][sum][st] = res;
}
ll count(ll x)
{
len = 0;
while(x)
a[ ++ len] = x % 10, x /= 10;
ll res = 0;
for (mod = 1; mod <= 9 * len; ++ mod) {
memset(f, -1, sizeof f);
res += dfs(1, 0, 0, 1);
}
return res;
}
int main()
{
scanf("%lld%lld", &l, &r);
printf("%lld\\n", count(r) - count(l - 1));
return 0;
}
以上是关于BZOJ 1799 [Ahoi2009] self 同类分布(数位DP)BZOJ千题计划(quexin的主要内容,如果未能解决你的问题,请参考以下文章
bzoj 1799: [Ahoi2009]self 同类分布
BZOJ 1799 [Ahoi2009] self 同类分布(数位DP)BZOJ千题计划(quexin
BZOJ 1799 [Ahoi2009] self 同类分布(数位DP)BZOJ千题计划(quexin