【郑轻oj】1837-LT说我不服(最大子序列的和)(好题)
2015-12-21 18:45
429 查看
1837: LT说我不服
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 53 Solved: 12
SubmitStatusWeb
Board
Description
对于上一道题目LT不服,表示那么简单的题目不屑于去做,所以我们决定加大一下题目的难度,下面是我们LT出的题目:假如给你一个由n个数组成的序列A1, A2, A3, A4 …… An。你可以选择任意一个大小的区间,将其中的每一个数x变成(x*1888+101)%14507。
求这n个数的最大和可能是多少。
Input
输入有多组数据每组数据第一行输入一个整数n为序列元素个数。(1 <= n <= 100000)
第二行n个整数A1, A2, A3, A4 …… An。(0 <= Ai <= 10000)
Output
每组样例输出一行答案。Sample Input
210000 999951 9999 1 9999 1Sample Output
1999921989HINT
范围在int内Source
LT系列第一次接触最小子序列的和的算法,提交两次,超时一次,第二次A了。
超时用了分冶的算法, 第二次的算法不好解释的通,我这里就自己写写试试吧(估计也只有自己懂了):从前往后逐项算和,不断地把最大的和保存入变量中,当和小于0时,便停止此轮的运算,从下一个数开始继续算和,直到结束。为什么可以这么算呢?根据个人的理解,既然每逢负数就从下一项开始重新计算,那么后面的最优解肯定是不包括前面的,而前面的最优解已经保存入变量中,如此筛选出被每个负数分开的子序列的和,最优解也一次次的更新,并不会漏解(感觉跟没说一样)。
先看超时代码吧,虽然超时了,但是分冶的思路还是挺好的:
TL代码:
#include <stdio.h> int a[100022],b[100022]; //原序列,相减得的子序列 int count_leftmax(int left,int center) //自定义函数:左边序列的最大和 { int max=0; int sum; if (left==center && b[left]<0) return 0; else { for (int i=left;i<=center;i++) { sum=0; for (int j=i;j<=center;j++) { sum+=b[j]; if (sum>max) max=sum; } } return max; } } int count_rightmax(int center,int right) //自定义函数:右边序列的最大和 { int max=0; int sum; center++; //center归左边 if (right==center && b[right]<0) return 0; else { for (int i=center;i<=right;i++) { sum=0; for (int j=i;j<=right;j++) { sum+=b[j]; if (sum>max) max=sum; } } return max; } } int count_doublemax(int left,int center,int right) { int max; int max1=0; int max2=0; int sum; //先算左边 if (left==center && b[left]<0) return 0; else { sum=0; for (int j=center;j>=left;j--) { sum+=b[j]; if (sum>max1) max1=sum; } } //再算右边 center++; if (right==center && b[right]<0) return 0; else { sum=0; for (int j=center;j<=right;j++) { sum+=b[j]; if (sum>max2) max2=sum; } } max=max1+max2; return max; } int cmp(int leftmax,int rightmax,int centermax) //取三个的最大值 { if (leftmax>rightmax) { if (leftmax>centermax) return leftmax; else return centermax; } else { if (rightmax>centermax) return rightmax; else return centermax; } } int main() { int n; int left,right,center; int leftmax,rightmax,centermax; int max; int sum; //用来对原数列相加 while (~scanf ("%d",&n)) { for (int i=1;i<=n;i++) { scanf ("%d",&a[i]); b[i]=(a[i]*1888+101)%14507; b[i]=b[i]-a[i]; } left=1; right=n; center=(left+right)/2; //中心的数归左边 leftmax=count_leftmax(left,center); rightmax=count_rightmax(center,right); centermax=count_doublemax(left,center,right); max=cmp(leftmax,rightmax,centermax); sum=0; for (int i=1;i<=n;i++) { sum+=a[i]; } sum+=max; printf ("%d\n",sum); } return 0; }
代码略长 — —! 但是思路还是很明确的,代码可以进一步优化。
下面是AC代码:
#include <stdio.h> int main() { int u; int a[100022],b[100022]; int max,tsum; while (~scanf ("%d",&u)) { for (int i=1;i<=u;i++) { scanf ("%d",&a[i]); b[i]=(a[i]*1888+101)%14507; b[i]=b[i]-a[i]; } max=0; tsum=0; for (int i=1;i<=u;i++) { tsum+=b[i]; if (tsum>max) max=tsum; if (tsum<0) { tsum=0; continue; } } int cot=0; for (int i=1;i<=u;i++) { cot+=a[i]; } cot+=max; printf ("%d\n",cot); } return 0; }
嗯挺短的!算法很重要!
相关文章推荐
- jQuery的attr与prop,attribute和property区别
- ERP
- cmd 到数据库时出现ORA-01658: 无法为表空间 DHCT中的段创建 INITIAL 区
- ZZULIOJ 1773 Lovely simple problem two
- Android控件_ProgressBar使用
- CLR和COM
- 在C#中调用视图
- 2015-12-21 FFC
- 17.利用UILabel制作输入框的剩余可输入文字提示信息
- Mozilla Firefox扩展(Extensions)开发——jpm
- UITouch
- 防止SQL注入
- online_judge_1133
- AJAX方法详解
- final关键字
- 3.IP协议,ARP协议,RARP协议
- 2.数据链路层
- 1.TCP/IP基本概念
- app崩溃后捕获异常或自动重启
- 【杭电】[2052]Picture