F



i



v



e



-



gr



ea



t
蓝桥杯历届试题K倍区间数(C语言)

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
数据规模和约定

思路:要求的是k的区间 而且是任意起点都可以,也就是随便截取区间只要是K的倍数即可。
那这里我们肯定得做取余运算了,如果余数为0当然是k的倍数了 那么余数不为0就不是K的倍数,
但是 仔细想一想 两个区间对k的取余结果相同,比如余数都为1时,此时这两个区间相减之后的
区间就是K的倍数了,但然这里不用担心,因为每次取到的都是连续的区间,所以减出来的区间也是连续的。
这里用到了sum来存余数x对应这个有y个区间,对于每种不同的区间他们的数量就是C(n,2),
就是n个里取两个相减,当然这里有特殊,就是余数为0的情况需要额外加1 因为 比如说S5就是K的倍数,他不需要减什么区间,但是在我们的运算中是要取到两个区间,所以要额外加1 相当于加了个 和为0的区间S0

#include <stdio.h>
int main()
{
  long int i,n,k,j,s,s1;
  long long sum[100001],js[100001]={0};
  sum[0]=0;long long ans=0;
  scanf("%ld%ld",&n,&k);
  for(i=1;i<=n;i++)scanf("%ld",&s),sum[i]=sum[i-1]+s; 
   js[0]=1;
    for(j=1;j<=n;j++)js[sum[j]%k]++;
    for(i=0;i<k;i++)if(js[i])ans+=(js[i]*(js[i]-1))/2;//C(n,2) 从 众多区间里选两个 都可构成 
printf("%lld\n",ans); 
return 0;
}