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 <mtext>    </mtext> m o d <mtext>    </mtext> 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 ) <mtext>    </mtext> m o d <mtext>    </mtext> 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 ) <mtext>    </mtext> m o d <mtext>    </mtext> 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;
}
全部评论

相关推荐

10-11 17:45
门头沟学院 Java
走吗:别怕 我以前也是这么认为 虽然一面就挂 但是颇有收获!
点赞 评论 收藏
分享
尊嘟假嘟点击就送:加v细说,问题很大
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务