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} 1ab1018

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}} st0(modsum)

但是这里 s t ≤ 1 0 18 \\mathrm{st}\\le 10^{18} st1018,显然无法枚举,题目中有模数 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}} st0(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的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ1799: [Ahoi2009]self 同类分布

bzoj 1799: [Ahoi2009]self 同类分布

BZOJ 1799 [Ahoi2009] self 同类分布(数位DP)BZOJ千题计划(quexin

BZOJ 1799 [Ahoi2009] self 同类分布(数位DP)BZOJ千题计划(quexin

BZOJ 1799: [Ahoi2009]self 同类分布 ( 数位dp )

手打AC的第2道数位DP:BZOJ1799: [Ahoi2009]self 同类分布