AtCoder Beginner Contest 146 E - Rem of Sum is Num(思维)

题目链接
给你一个长度为 n n n的序列,和一个 k k k.
询问你有多少个区间 [ l , r ] [l,r] [l,r],满足 ∑ i = l r a i    m o d    k = r − l + 1 \sum_{i=l}^ra_i ~~mod~~k=r-l+1 i=lrai  mod  k=rl+1

我们把题目要求的式子转化一下就是 ∑ i = l r a i − ( r − l + 1 )    m o d    k = 0 \sum_{i=l}^ra_i-(r-l+1) ~~mod~~k=0 i=lrai(rl+1)  mod  k=0

那么我们枚举右端点,看每个右端点有几个符合的左端点。
我们先记录前缀和。
然后枚举右端点 r r r:要找到所有 l l l满足 ∑ i = 1 r a i − ( r ) ≡ ∑ i = 1 l − 1 a i − ( l − 1 )    m o d    k \sum_{i=1}^ra_i-(r) \equiv \sum_{i=1}^{l-1}a_i-(l-1) ~~mod~~k i=1rai(r)i=1l1ai(l1)  mod  k
那么很显然了, m a p map map记录一下每个前缀和-下标出现的次数即可!

注意:因为区间长度必须严格小于 k k k才满足,所有我们要把超过的部分给去掉!

细节见代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
int n,k,a[N];
LL s[N],t[N];
map<int,int>vis;
int main() {
    ios::sync_with_stdio(false);
    cin>>n>>k;
    for(int i=1;i<=n;i++)cin>>a[i],s[i]=s[i-1]+a[i],s[i]=(s[i]+k)%k;
    LL ans=0;
    vis[0]=1;
    int l=0;
    for(int i=1;i<=n;i++){
        while(i-l>=k){
            vis[(s[l]-l%k+3ll*k)%k]--;//相当于找到一段区间的sum-len=0 (%k )
            l++;
        }
        ans+=vis[(s[i]-i%k+3ll*k)%k];
        vis[(s[i]-i%k+3ll*k)%k]++;
    }
    cout<<ans<<'\n';
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值