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;
}
267

被折叠的 条评论
为什么被折叠?



