题意:有一条长为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;
}
}
}