对于上一道题目LT不服,表示那么简单的题目不屑于去做,所以我们决定加大一下题目的难度,下面是我们LT出的题目:
假如给你一个由n个数组成的序列A1, A2, A3, A4 …… An。你可以选择任意一个大小的区间,将其中的每一个数x变成(x*1888+101)%14507。
求这n个数的最大和可能是多少。
每组样例输出一行答案。
范围在int内
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; }