[ABC146E] Rem of Sum is Num



[ABC146E] Rem of Sum is Num - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

给定一个序列和一个正整数K,求这个序列有多少子区间满足:子区间所有元素和S除以K的余数是子区间的长度。

子区间元素和——>前缀和。

对于这个公式,有如下的化简推导

S[i]-S[j]= k*a+i-j(a为常数)。

S[i]-i-(S[j]-j)=k*a

(S[i]-i) \%k=(S[j]-j)\%k

所以去找(sum_{i}-i) \mod k 相同的个数。

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

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值