[Acwing蓝桥杯贪心] 1248. 灵能传输
大概题意:给一个长度为数列,除了两个端点以外,任意选一个点,可以将该点的值分给相邻的两个点,也可以得到相邻的两个点的值
整个数列的总能量不变 就是能量输出给相邻的点或者从相邻的点输入。
分析:
这是一个贪心题,时间复杂度 倒不是问题 关键点是思路
这个题有三个难点,不太好想的地方:
设 每个点的元素 都存在 数组a[ ] 中
1、要考虑到前缀并且探究到前缀和的规律
规律:
假设这个数组的前缀和为: s[1], s[2] ... s[n]
如果 点 i 的能量与相邻的点 i - 1 和 i +1 传递 那么 就是 a[ i ] -= 2 * a[ i ] , a[ i-1] += a[ i ] , a[ i+1] += a[ i ] ;//适应于a[ i ]无论正负
那 么 s [ i+1]大小是没有变的 ,s [ i - 1] 多了个 a[ i ] , s [ i ] 减去了两个 a [ i ] , 相当于 减去相对多出的一个a[ i ],又少了个a[ i ]
s [ i-1] 变成了 s[ i ] , s[ i ] 变成了 s[ i-1]
对应到函数上就是 除了起始的点两个点不能交换 最后面的两个点不能交换 任意的两个 a[ i ]和a[ i-1]可以互换。
2、因为开始的起点不变,最后的终点不能变
这里用了贪心的思想
那么当图形是这样时候 是最好的
3、最后,如何确定s0和sn直接的排序
代码如下:
查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=300010;
int n;
LL a[N],s[N];
bool st[N];
int main()
{
int T;
cin>>T;
while(T--)
{
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
s[i]=s[i-1]+a[i];
}
LL s0=s[0],sn=s[n];
if(s0>sn)swap(s0,sn);
sort(s,s+n+1);
for(int i=0;i<=n;i++)
{
if(s[i]==s0)
{
s0=i;
break;
}
}
for(int i=n;i>=0;i--)
{
if(s[i]==sn)
{
sn=i;
break;
}
}
memset(st,0,sizeof st);
int l=0,r=n;
for(int i=s0;i>=0;i-=2)
{
a[l++]=s[i];
st[i]=1;
}
for(int i=sn;i<=n;i+=2)
{
a[r--]=s[i];
st[i]=1;
}
for(int i=0;i<=n;i++)
{
if(!st[i])a[l++]=s[i];
}
LL res=0;
for(int i=1;i<=n;i++)
{
res=max(res,abs(a[i]-a[i-1]));
}
printf("%lld\n", res);
}
return 0;
}
end!!!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)