【Luogu】P4127 [AHOI2009] 同类分布 (数位DP)

P4127 [AHOI2009] 同类分布 - 洛谷

题目:

思路:

数位DP板子

一看到统计符合某个特征的数字,那么显然可以想到数位DP

那么板子走起,首先当前位 now 和 lim 肯定有,本题没有前导零的限制,所以可以不需要

那么就分析题目条件来知道还要加什么参数,既然要满足所有 数字 能被 数位和 整除,那么显然就需要数位和 sum 这个参数,那么如何处理 数字 能被 数位和整除这个条件呢?如果其当作一个参数,那么记忆化时显然会爆内存,所以考虑优化

发现 18*9=162,数位和的可能很小,所以我们可以考虑提前枚举我们最后的数位和 givesum,那么计算过程中我们只需要传当前的余数 mod 了,这样一来就能快速优化了

PS:下面的代码不应该偷懒使用字符串的,多测时会计算错误,因为我们的最高位是 0,多测记忆化时显然会读取错误,本题不知道为什么能过,应该改成数组比较好的

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define yes cout << "YES\n"
#define no cout << "NO\n"
#define Sunny 0
mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());

int dp[20][205][205];
int A,B, m, givesum;
string a;

int dfs(int now, int lim, int sum, int mod)
{
    if (now == m)
        return sum == givesum && !mod;
    if (dp[now][sum][mod] != -1 && !lim)
        return dp[now][sum][mod];
    int mx = lim ? a[now] - '0' : 9;
    int res = 0;
    for (int i = 0; i <= mx; i++)
    {
        if (i + sum > givesum)
            break;
        res += dfs(now + 1, lim && i == mx, sum + i, (mod * 10 + i) % givesum);
    }
    if (!lim)
        dp[now][sum][mod] = res;
    return res;
}

int getans(int x)
{
    a = to_string(x);
    m = a.size();
    int ans = 0;
    for (int i = 1; i <= 9 * m; i++)
    {
        memset(dp, -1, sizeof dp);
        givesum = i;
        ans += dfs(0, 1, 0, 0);
    }
    return ans;
}

void solve()
{
    cin >> A >> B;
    cout << getans(B) - getans(A-1) << endl;
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t = 1;
	while(t--)
    {
        solve();
    }
    return Sunny;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值