您的位置:首页 > 其它

蓝桥杯_历届试题 k倍区间

2018-03-27 19:17 274 查看
问题描述  给定一个长度为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数据规模和约定  峰值内存消耗(含虚拟机) < 256M
  CPU消耗 < 2000ms

  请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。

  注意:
  main函数需要返回0;
  只使用ANSI C/ANSI C++ 标准;
  不要调用依赖于编译环境或操作系统的特殊函数。
  所有依赖的函数必须明确地在源文件中 #include <xxx>
  不能通过工程设置而省略常用头文件。

  提交程序时,注意选择所期望的语言类型和编译器类型。

   这个题在之前的一次训练赛上做过一次,记得当时已经对前缀和进行了取余,但是后面的那一小点点实在就是没有想出来,这次突然又在蓝桥杯中看到了这个题,很是愉快的就把后面的最后一点写了出来。
    我们首先要知道前缀和,就是:sum[1] = a[1];
sum[2] = a[1] + a[2];
sum[3] = a[1] + a[2] + a[3];
......这样我们就可以携写成:
sum[i] = a[i] + sum[i-1];
我们对sum进行取K的余数运算,那么我们得到的就是就在区间[0,k)之间,我们称取余之后的数组为num数组,最后最重要的一小点就是:我们发现num数组中的每两个相同数字之间的区间,这个区间的和就是一个K的倍数,比如:我们对3进行取余,sum数组是[0,1,2,6,10,15],num数组是[0,1,0,0,1,0];我们发现在两个1之间的数组就是在求和之后,他们对于3的余数是相等的,那么这个区间之见一定差的就是3的相应的倍数了。这样我们就理解了,这个题的做法了。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
#include <set>
#define ll long long
using namespace std;
const int MAXN = 100100;
ll N,K;
ll a[MAXN];
ll sum[MAXN];
ll num[MAXN];

//我们首先要进行求和,然后对每一项求和进行取余,然后我们会会发现非0的相同的数之间的区间就是k的倍数
int main()
{
scanf("%I64d%I64d",&N,&K);
memset(sum,0,sizeof(sum));
memset(num,0,sizeof(num));
for(int i =1;i <= N;i ++)
{
scanf("%I64d",&a[i]);
sum[i] = (a[i] + sum[i-1]) % K;
}
for(int i = 0;i <= N;i ++)
{
num[sum[i]] ++;
}
ll ans =0 ;
for(int i = 0;i <K;i++)
{
ans += (num[i]-1)*num[i]/2;
}
printf("%I64d\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息