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