[ 第八届蓝桥杯省赛C++B组]K倍区间 原创

来源: 第八届蓝桥杯省赛C++B组
算法标签:前缀和
题目描述

给定一个长度为 N 的数列,A1,A2,…AN,如果其中一段连续的子序列 Ai,Ai+1,…Aj 之和是 K 的倍数,我们就称这个区间 [i,j] 是 K 倍区间。

你能求出数列中总共有多少个 K 倍区间吗?

输入格式

第一行包含两个整数 N 和 K。

以下 N 行每行包含一个整数 Ai。

输出格式

输出一个整数,代表 K 倍区间的数目。

数据范围
1≤N,K≤100000,
1≤Ai≤100000
输入样例:
5 2
1
2
3
4
5
输出样例:
6
C++ 代码

o(n^3) 枚举

    for(int r = 0;r<=n;r++)
        for(int l = 0;l<=r;l++)
            {
            int sum =0 ;
                for(int i = l;i<=n;i++)
                    sum+=s[i];
                if(sum % k == 0) ans++;
            }

前缀和 o(n^2)

    for(int r = 0;r<=n;r++)
        for(int l = 0;l<=r;l++)
            if((st[r] - st[l-1]) %k == 0)//相当于计算多少个st[r%k] == st[l-1%k],==特定值x
                ans++;

o(n)

#include<iostream>

using namespace std;

typedef long long LL;
const int N=1e5+10;
LL cnt[N],s[N];
int n,k;
LL ans;

int main()
{
    cin>>n>>k;
    for(int i=1;i<=n;i++)//基于o(n) st[r%k] == st[l-1%k],实际是省掉上一个方法的一层循环
        {
            cin>>s[i];
            s[i]=(s[i-1]+s[i])%k;//前缀和
            ans+=cnt[s[i]];//更新答案,cnt%k存储当前余数的次数
            cnt[s[i]]++;//加上当前余数相同的情况
        }
    cout<<ans+cnt[0];//加上余数为零的情况
    return 0;
}
posted @ 2022-05-13 01:12  俺叫西西弗斯  阅读(0)  评论(0)    收藏  举报  来源