D. The Enchanted Forest

传送门:
D. The Enchanted Forest

题意:有一条长为n的线段,每个点上起始有a[i]个蘑菇。你可以选择起始点x。你有k分钟,每分钟以下事件将会发生:

1.从点x走到点y(abs(y-x)<=1)

2.收集点y上的蘑菇

3.所有点上新长出一个蘑菇

求k分钟能够收集的最大蘑菇数。

分析1:赛时想的是枚举起点和方向,每次走到端点再调头,需要分类讨论一下。只写了往右走的居然直接过了。赛后知道了正解才知道没影响,运气真的好。

代码1:
 

#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[200005];
int pre[200005];

int sum(int x)
{
    return (1+x)*x/2;
}

signed main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n,k;
        cin>>n>>k;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            pre[i]=pre[i-1]+a[i];
        }
        if(n==1)
        {
            cout<<a[1]+(k-1)<<endl;
            continue;
        }
        int maxx=0;
        for(int x=1;x<=n;x++)
        {
            int y=k;
            int ans=0;
            if(y<=n-x+1)
            {
                ans+=pre[x+y-1]-pre[x-1]+sum(y-1);
                maxx=max(maxx,ans);
            }
            else
            {
                int yy=n-x+1;
                ans+=pre[x+yy-1]-pre[x-1]+sum(yy-1);
                y-=yy;
                if(y<=n-x)
                {
                    ans+=2*sum(y);
                    maxx=max(maxx,ans);
                }
                else
                {
                    int cc=n-x;
                    ans+=2*sum(cc);
                    y-=cc;
                    if(y<=x-1)
                    {
                        ans+=pre[x-1]-pre[x-1-y]+y*2*(n-x)+sum(y);
                        maxx=max(maxx,ans);
                    }
                    else
                    {
                        int zz=x-1;
                        ans+=pre[x-1]-pre[x-1-zz]+zz*2*(n-x)+sum(zz);
                        y-=zz;
                        int cnt=y/(n-1);
                        int rem=y%(n-1);
                        ans+=cnt*2*sum(n-1);
                        ans+=2*sum(rem);
                        maxx=max(maxx,ans);
                    }
                }
            }
        }
        cout<<maxx<<endl;
    }
}

分析2:对于k<=n的情况,直接找最大的子区间。否则,贪心的只走最后n分钟(采一遍)。

代码2:
 

#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[200005],pre[200005];

signed main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int n,k;
        cin>>n>>k;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            pre[i]=pre[i-1]+a[i];
        }
        if(k<=n)
        {
            int maxx=0;
            for(int i=1;i<=n;i++)
            {
                if(i>=k)
                {
                    maxx=max(maxx,pre[i]-pre[i-k]);
                }
            }
            cout<<maxx+(1+k-1)*(k-1)/2<<endl;
        }
        else
        {
            int ans=pre[n]+((k-n)+(k-1))*n/2;
            cout<<ans<<endl;
        }
    }
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chmpy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值