[ABC146E] Rem of Sum is Num - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
给定一个序列和一个正整数K,求这个序列有多少子区间满足:子区间所有元素和S除以K的余数是子区间的长度。
子区间元素和——>前缀和。
对于这个公式,有如下的化简推导
(a为常数)。
所以去找 相同的个数。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define inf 0x3f3f3f3f
#define pii pair<int,int>
void solve(){
int n,k;
cin>>n>>k;
vector<int>a(n+1,0);
//计算区间前缀和。
for(int i=1;i<=n;i++){
int x;
cin>>x;
x%=k;
if(i==1){
a[i]=x;
}else{
a[i]=a[i-1]+x;
}
}
//map储存相同的计算结果。
map<int,int>u;
int sum=0;
for(int i=1;i<=n;i++){
//重新定义每个元素的值。以便后面进行。
a[i]=(a[i]-i)%k;
}
//¥因为他是和k进行取余后的结果要等于区间长,所以若n>k那么每个区间长度最大就为k-1,若n<=k那么最大长度就是n.
//确定这个点的目的是为了区分区间静止和区间移动两个过程。
int pos=min(n,k-1);
//由于区间长本身就小于最大值,所以对于每一个点,他都可以和之前已经出现过的相同的点来构成一对区间。
//sum+的就是这个可能的区间有多少。
for(int i=0;i<=pos;i++){
sum+=u[a[i]];
u[a[i]]++;
}
//现在已经移动到了最大区间外,那么区间之前(被遗弃的)i-k位置的数就不能再用了。那个 位置的数要-1,代表少了一种区间形成结果。
for(int i=pos+1;i<=n;i++){
u[a[i-k]]--;
//现在的sum+的是更新后的可生成区间数目。
sum+=u[a[i]];
//区间遗弃开头后,有保留进结尾。
u[a[i]]++;
}
//结束了。
cout<<sum<<endl;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
int oyyo=1;
//cin>>oyyo;
while(oyyo--) {
solve();
}
return 0;
}