一二三四五 上山打老虎

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;
}
posted @ 2021-01-22 17:18  黒川川  阅读(164)  评论(0)    收藏  举报