【信息学竞赛真题! ! !】信息学竞赛人必看的「USACO2016」Subsequences Summing to Sevens题解(C++版)

朋友们好!今天要和大家分享的是一个有趣的题,这是2016年美国信息学奥赛USACO一月赛季的题目,中文名叫“与7无关的数”,你将在本文中了解到前缀和的知识,并且了解到一道难题是怎么做出来的。(注,这是一个困难的过程)

(本文适合学习C++有那么一点点基础,但基础又不是特别高的朋友)

A.题目描述

题目描述

给你n个数,分别是a[1],a[2],…,a[n]。求一个最长的区间[x,y],使得区间中的数(a[x],a[x+1],a[x+2],…,a[y-1],a[y])的和能被7整除。输出区间长度。若没有符合要求的区间,输出0。

输入

第一行一个数n,接下来为n个数,每个数在0~1000000范围内,1<=n<=50000

输出

输出最大区间长度

样例输入
7
3 5 1 6 2 14 10

样例输出
5

提示

来源
USACO2016JAN

B.初步分析

一开始你看到这道题是什么感受呢?你会不会说:这道题不就是道枚举题嘛,so easy!

1.0版方法

for(int i=1;i<=n;i++){
   
	for(int j=i;j<=n;j++){
   
		for(int k=i;k<=j;k++){
   
			s+=a[k];
		}
		if(s%7==0)
			m=max(j-i,m);
		s=0;
	}
}

可是,注意一下数据范围,三重循环,明晃晃的超时呀!
于是,你是否人有了改进枚举的想法——

1.5版方法

for(int i=1;i<=n;i++){
   
	int s=0;
	for(int j=i;j<=n;j++){
   
		s+=a[j];
		if(s%7==0)
			m=max(j-i,m);
	}
}

看上去好些了,那么让我来告诉自信的你,时间超限了……

等等,换种思维试试——

1.7版方法

for(int i=1;i<=n;i++){
   
	int s=0;
	for(int j=n;j>=i;j--){
   
		s+=a[j];
		if(s%7==0){
   
			m=max(j-i,m);
			break;
		}
	}
}

哈哈,从今以后请记住:不狡猾的出题人是不聪明的。单纯地用枚举,无论怎样都会时间超限……

C.算法改进

这时,总算有人想起前缀和与差分。
前缀和直接就求出了1~i之间的所有数值和,不是很好用吗?

(不懂得前缀和的朋友,请直接把文档拉到底部E.3处。)

2.0版方法

for(int i=1;i<=n;i++){
   
	scanf("%lld",&a[i]);//注意,a[i]太大,要用long long定义,也就得用lld输入
 	b[i
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值