ABC 367D Pedometer

题意
给定N个人成的环,第i个人到第i+1个人之前的距离为a[i](第N个人到第1个人的距离为a[n]),每个人只能顺时针走动。求问有多少点对(s,t)使得第s个人走到第t个人的距离是M的倍数。

思路
对于这种环状问题,我们最开始的思路就是开个双倍数组把环破坏成链转换成线性问题。接下来就是我们要思考的一个问题是,第i个人可以走向其他的N-1个人,我们要枚举N个人,最为暴力的方法肯定是O(N^2)的,显然无法通过,那么我们注意到:当你顺序枚举其中一个人到他下一个人的时候,其实只有两个元素发生了变化:一段长度为N-1的区间的左端点被筛除,区间右端点的紧接元素被纳入到这个区间,仔细思考可以得出:这不就是滑动窗口嘛?我们可以采取双指针的策略维护这个滑动窗口。并采取前缀和+取模的形式来维护即可。具体的细节就看代码吧

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=4e5+10;
int a[maxn],sum[maxn],ans;
map<int,int>much;

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i+1];
		a[i+1+n]=a[i+1];
	}
	for(int i=1;i<=2*n-1;i++) sum[i]=(sum[i-1]+a[i])%m;
	for(int i=n+1;i<=2*n-1;i++) much[sum[i]]++;
	int flag1=n;
	int flag2=2*n-1;
	int turn=0;
	while(turn<n)
	{
		int x=sum[flag1];
		ans+=much[x];
		much[sum[flag1]]++;
		much[sum[flag2]]--;
		flag1--;
		flag2--;
		turn++;	
	}
	cout<<ans<<endl;
	
	return 0;
 } 
posted on 2024-08-18 22:13  Linear_L  阅读(11)  评论(0编辑  收藏  举报