题解:AT_abc367_d [ABC367D] Pedometer

首先肯定要单层循环枚举元素,然后想方法求出一个元素的所有答案。

一开始我写了一个二分找 m 倍数的方法,发现 m 小的时候还不如暴力。

于是联想到之前做过的一道题,可以借助于取模的前缀和数组。

对于当前元素 i,如果一个元素之前的前缀和与 i 之前的前缀和对 m 取余后相同,那么说明中间的所有元素的和一定是 m 的倍数。

有了这个思路,我们可以着手想代码了。首先二倍数组断环成链,然后计算前缀和数组 sum。用一个 cnt 数组记录前缀和对 m 取模后的值为一定值的个数。

在枚举 i 的时候,我们可以从 n+1 枚举到 2n。该元素对答案的贡献显然就是 cntsumimodm。但需要注意的是,计算过 i 的贡献之后,i 就不能对以后的答案产生新贡献了,同时为保证找到的数字距离 i 不超过 n,我们对 cnt 数组进行更新,具体的,我们让 cntsumin+1modmcntsumimodm++。这样使得 cnt 一直表示的是 in+1i 之间的结果。

Code

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
	int w=1,s=0;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') w=-1;ch=getchar();}
	while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
	return w*s;
}
const int maxn=1e6+10;
const int mod=1e9+7;
int n,m;
int a[maxn];
int sum[maxn],ans=0;
map<int,int> cnt;
signed main()
{
//	freopen("xxx.in","r",stdin);
//	freopen("xxx.out","w",stdout);
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		a[i]=read();
		a[i+n]=a[i];
	}
	for(int i=1;i<=n*2;i++)
	{
		sum[i]=sum[i-1]+a[i];
	}
	for(int i=2;i<=n;i++)
	{
		cnt[sum[i]%m]++;
	}
	for(int i=n+1;i<=2*n;i++)
	{
		ans+=cnt[sum[i]%m];
		cnt[sum[i-n+1]%m]--;
		cnt[sum[i]%m]++;
	}
	cout<<ans;
	return 0;
}
posted @   Redamancy_Lydic  阅读(23)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示