题解 luogu.P4127 [AHOI2009] 同类分布

题目

luogu.P4127 [AHOI2009] 同类分布

题意建模

还是一样。以后打蓝题及以上,先打暴力,再看正解。

所以这个部分就直接说暴力的思路了。

直接按照题意模拟,这里是完全在线的算法,但是我觉得可以尝试优化一下。

  • 先预处理一个数据范围(比如说 \(1e8\) 这个范围内的数据,提前开一个大数组存储),这样询问的时候,直接 \(O(1)\) 查询,\(O(len)\) 预处理计算(这里的 \(len\) 是数字的位数,最多不超过20,所以这一部分也约等于\(O(1)\))。
  • 但是,由于数据范围过大,这样比直接完全在线好不了不少,因为如果是前者,时间复杂度为 \(O(N\times len)\),只能过去大约 \(1e7\) 的数据,所以肯定超时;又由于空间的上线是 \(1e8\),所以最终得分两种方法优化几乎微乎其微。

这就是暴力的思路。原题数据范围有 \(1e18\),所以期望得分 \(30pts-50pts\)

算法分析

数位DP。

如何处理?考虑枚举每一个数,核心思想就是下面的一句话:

整除某个数等价于对这个数取余数为0.

所以,我们只需要存储下来这个数每一位上的数字,然后逐位枚举,在记忆化搜索的时候增设一维参数,考虑这个当前的局面下,是否取的余数为0。当然,这是在递归出口的时候判断,因为我们是逐位枚举,所以应该模拟十进制数加法进位的规则,对应的代码是以下这一句:
if(!pos) return (sum==t&&rest==0)?1:0;
这一句就是判断,在当前这个数处理完之后,rest变量累加的结果是否是0。
具体的判断还要结合中间递归过程的代码:
for(int i=0;i<=top;i++) ans+=dfs(pos-1,sum+i,(rest*10+i)%t,limit&&i==top);
我们主要看增设的参数rest,每一次为了防止爆掉long long,我们在扩展状态时,会对其取模。

参考代码

暴力40pts

#include<iostream>
#define int long long
using namespace std;
inline int solve(int x)
{
	int ans=0;
	while(x)
	{
		ans+=x%10;
		x/=10;
	}
	return ans;
}
signed main()
{
	int a,b; cin>>a>>b;
	int ans=0,cnt=0;
	for(int i=a;i<=b;i++)
	{
		int x=solve(i);
		if(i%x==0) cnt++;
	}
	cout<<cnt<<endl;
	return 0;
}

正解100pts

#include<iostream>
#include<cstring>
#define int long long
using namespace std;
const int N=21;
int dp[N][200][200],num[N];//21*9<200
int t,a,b;
int dfs(int pos,int sum,int rest,bool limit)
{
	if(!pos) return (sum==t&&rest==0)?1:0;
	//最终取模等于0,说明是一个合法解,返回1累加,不然就返回0
	if(!limit && dp[pos][sum][rest]!=-1) return dp[pos][sum][rest];
	int top=limit?num[pos]:9,ans=0;
	for(int i=0;i<=top;i++) ans+=dfs(pos-1,sum+i,(rest*10+i)%t,limit&&i==top);
	if(!limit) dp[pos][sum][rest]=ans;
	return ans; 
}
int solve(int x)
{
	int idx=0,ans=0;
	while(x) num[++idx]=x%10,x/=10;
	for(t=1;t<=idx*9;t++)
	{
		memset(dp,-1,sizeof(dp));
		ans+=dfs(idx,0,0,true);
	}
	return ans;
}
signed main()
{
	cin>>a>>b;
	cout<<solve(b)-solve(a-1)<<endl;
	return 0;
}

细节实现

大部分的细节都在算法分析中讲得够清楚了,所以这里就不再赘述。

总结归纳

其实没甚好总结的,就是要掌握这种思维,然后尝试模仿并应用。

posted @ 2025-08-01 08:42  枯骨崖烟  阅读(6)  评论(0)    收藏  举报