【蓝桥杯第八届B组省赛】k倍区间
一、题目
给定一个长度为N的数列,A1, A2, … AN,如果其中一段连续的子序列Ai, Ai+1, … Aj(i <= j)之和是K的倍数,我们就称这个区间[i, j]是K倍区间。
你能求出数列中总共有多少个K倍区间吗?
输入格式
第一行包含两个整数N和K。(1 <= N, K <= 100000)
以下N行每行包含一个整数Ai。(1 <= Ai <= 100000)
输出格式
输出一个整数,代表K倍区间的数目。
输入格式
5 2
1
2
3
4
5
程序应该输出:
6
二、解法分析
1.同余定理
对于两个整数a,b,给定一个正整数d,若(a-b)%d=0,也就是(a-b)能够被d整除,那么我们就说a和b是模d同余的,记为a≡b(mod d)。
例如a=7,b=2,c=5。由于(7-2)%5==0,所以7和2是模5同余的。
2.本题的解法
我的解法是前缀和+同余定理,需要开一个余数数组sum,表示每个余数的数量。初始化余数数组,即sum[0]=1(0的数量设为1),其他余数数量均设为0。每计算完前i(1<=i<=n)个数的前缀和时,求出该前缀和模k得到的余数u,然后根据同余定理,在第i个数之前,模k后余数为u的前缀和个数=在第i个数之前的能够整除k的区间个数(区间包括第i个数),这个个数即为sum[u]。在遍历下个数之前,还需要更新余数数组,即sum[u]=sum[u]+1。
三、代码
代码比解法分析更清晰明了。
#include <bits/stdc++.h>
using namespace std;
long long sum[100009];//余数数组
long long sumed;
long long a[100009];
long long all;
int main()
{
long long i;
long long n;
long long k;
sum[0]=1;
cin>>n;
cin>>k;
for(i=1;i<=n;i++)
{
cin>>a[i];
sumed=sumed+a[i];
long long u=sumed%k;
all=all+sum[u];
sum[u]++;
}
printf("%lld\n",all);
return 0;
}