NC15553-数学考试
题目链接:https://ac.nowcoder.com/acm/problem/15553
题意:总共n道题,每道题的得分是ai,从中选取两个不相交且长度分别为k的区间的题目来做,保证得到的分数尽可能的多。
思路:
1:假算法: 简单贪心,先从n个选取一个长度为k且区间和最大的区间,然后在此区间左右两侧选择另一个长度为k且区间和最大的区间(可能数据比较水,如果有另外两个区间的和大于本算法所选取的区间呢?)复杂度O(N)
2:
坑点:n个整数中有负数,导致最大分数可能是负数,所以最大分数默认值要设为极小负数。
反思:真算法中的遍历方法相当于把两个for循环优化成了一个for循环,对于两个k区间一定是一个在左边一个在右边,结果一定是两个区间和最大的结果,并非假算法的结果。
假算法:
#include<cstdio>
#include<algorithm>
using namespace std;
long long a[(int)2e5+5]={0};
int main (){
int t,n,k;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
a[i]+=a[i-1];
}
if(n<=2*k)printf("%lld\n",a[n]);
else {
long long ansa=-999999999999999,ansb=-999999999999;
int r=k;
for(int i=k;i<=n;i++){
if(a[i]-a[i-k]>ansa){
ansa=a[i]-a[i-k];
r=i;
}
}
int l=r-k+1;
for(int i=1;i+k-1<l;i++)
ansb=max(ansb,a[i+k-1]-a[i-1]);
for(int i=r+1;i+k-1<=n;i++)
ansb=max(ansb,a[i+k-1]-a[i-1]);
printf("%lld\n",ansa+ansb);
}
}
return 0;
}
真算法:
#include<iostream>
using namespace std;
long long a[(int)2e5+5];
int main (){
int t;
cin>>t;
while(t--){
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
a[i]+=a[i-1];
}
long long ff=-99999999999999,ss=ff;
for(int i=k;i+k<=n;i++){
ff=max(ff,a[i]-a[i-k]);
ss=max(ss,ff+a[i+k]-a[i]);
}
cout<<ss<<endl;
}
return 0;
}

浙公网安备 33010602011771号