第八届蓝桥杯第十题--k倍区间(C语言)

第八届蓝桥杯第十题–K倍区间(C语言)

一.比赛题目

1.题目要求

给定一个长度为N的数列,A1, A2, … AN,如果其中一段连续的子序列Ai, Ai+1, … Aj(i <= j)之和是K的倍数,我们就称这个区间[i, j]是K倍区间。 你能求出数列中总共有多少个K倍区间吗?

2.输入与输出

输入:
第一行包含两个整数N和K。(1 <= N, K <= 100000) 以下N行每行包含一个整数Ai。(1 <= Ai <= 100000)
输出:
输出一个整数,代表K倍区间的数目。
样例输入:
5 2
1
2
3
4
5
样例输出:
6

二.分析过程

1.总体分析

这道题一眼就能看懂,双重for循环,一个i=0到n,一个j=i+1到n,就可以把这个结果求出来;但是就这道题而言,1 <= N, K <= 100000,所以肯定会超时。问题就在于如何节省时间;
在前段时间学习了动规,背包之后,有了填表,拆分成子问题来解决的一种思想。

2.问题分析

就样例输入而言,可以把1-5来进行填表:

序号12345
数字12345
总和1361015

因为第一个数字需要考虑1,1+2,1+2+3,1+2+3+4等情况,而最后一个数字仅需要考虑5他本身,所以我们采用逆推的想法来填表:

序号12345
数字12345
递减总和15141295

我们得到:第i个递减总和–第i+3个递减总和,就是第i个–第i+2个数字的连续区间之和
例如第二个数字的递减总和–第五个数字的递减总和=第二个到第四个连续区间相加的总和;
第二个数字的递减总和–第四个数字的递减总和=第二个到第三个连续区间相加的总和;

第n个数字:

满足条件
不满足条件
n
sum++
sum不变

第n-1个数字:

满足条件
不满足条件
不满足条件
满足条件
n-1
sum++
an-1-an
sum不变

注:不满足条件时是a[n-1]-a[n],即为倒数第二个;

通过递推,我们发现了第i个开始的连续区间可以用这种方式来表示,所以就能够节约下来双重for循环的时间;
代码如下:

for(int i=n-1;i>=0;i--)
	{
		if(c[i]%k==0)
			sum++;
		for(int j=n-1;j>i;j--)
		{
			if((c[i]-c[j])%k==0)
				sum++;
		}
	}
	//c[i]就是表里面递推的总和;

三.整体代码

#include<stdio.h>

int main()
{
	int n,k;
	scanf("%d %d",&n,&k);
	int sum=0;
		//记录输入数据的总和;
	int count=0;
		//记录k倍区间的数目;
	int a[n],c[n];
	for(int i=0;i<n;i++)
		{
		scanf("%d",&a[i]);
		sum+=a[i];
	}
		//输入数据且计算总和;
	c[0]=sum;
		//第一个数赋值为全部数的总和;
	for(int i=1;i<n;i++)
	{
		c[i]=c[i-1]-a[i-1];
	}
		//递减总和;
	for(int i=n-1;i>=0;i--)
	{
		if(c[i]%k==0)
			count++;
		for(int j=n-1;j>i;j--)
		{
			if((c[i]-c[j])%k==0)
				count++;
		}
	}
		//条件筛选;
	printf("%d",count);
	return 0;
 } 
//其实每次从后向前递推
//这样也能过的
#include<stdio.h>
int n,k,a[100010];
int main()
{
	int num=0;
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for(int i=1;i<=n;i++)
	{
		int sum=0;
		for(int j=i;j>=1;j--)
		{
			sum+=a[j];
			if(sum%k==0)
			num++;
		}
	}
	printf("%d",num);
	return 0;
}

四.总结

这道题是会了算法思想之后再来看的一道题,虽然没有用到,但是在解决问题的时候递推观察还是挺有帮助的。接下来就要学习其他的算法和做题了。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值