【题解】[POI2008] BBB-BBB

题意

给定一个由+1和−1构成的长度为n的序列,提供两种操作:

1.将某一位取反,花销为x

2.将最后一位移动到第一位,花销为y

要求最终p+sumn=q,且p+sumi≥0(1≤i≤n),求最小花销

sumi为1-i的前缀和

Solution:

考点:贪心+分析性质。

首先考虑将后面一段接到前面,容易想到 O(n) 枚举分割点。

然后 p+sum[i]>=0 的话,找到 minsum[i] ,每次 +2 直到 minsum[i] >= -p 。最后算一下 abs(sum[n]-q)/2 求偏移量即可。(每次贪心地在序列尾部修改应该没什么问题吧)。

问题转化为 滑动区间求最小值 ,可以用单调队列维护。具体地,首先剖成 2*n 长度的链,然后维护整体偏移量 delta 即可。

时间复杂度 O(n) 。有更简洁的实现方法,可以不用单调队列,参见 k c z n o 1 kczno1 kczno1 的博客。

#include<bits/stdc++.h> #define ll long long #define INF 0x3f3f3f3f #define PII pair<int,int> using namespace std; const int mx=2e6+5; int n,p,Q,A,B,head,tail,q[mx],sum[mx],res[mx],b[mx],delta; ll ans(-1); char a[mx]; int main() { scanf("%d%d%d%d%d%s",&n,&p,&Q,&A,&B,a+1); int tmp(p); for(int i=1;i<=n;i++) { if(a[i]=='+') tmp++; else tmp--; } //首先考虑将后面一段接到前面 //可以 O(n) 枚举 , 然后从前到后扫一遍 ,每次把一个 '-' 换成 '+' ,最后再从后往前把它替换回来 //这个性质相当于求出 minsum_i ,每次 +2 直到 minsum_i >= -p a[n+1]=a[1]; for(int i=1;i<=n;i++) { a[i]=a[i+1]; b[i]=(a[i]=='+')?1:-1; b[i+n]=b[i]; } head=1,tail=0; for(int i=1;i<2*n;i++) { if(i>=n) delta+=b[i-n]; sum[i]=sum[i-1]+b[i]; res[i]=delta+(i<=n)?sum[i]:sum[i]-sum[i-n]; while(head<=tail&&q[head]<=i-n) head++; while(head<=tail&&res[q[tail]]>=res[i]) tail--; q[++tail]=i; if(i>=n) { ll Min=res[q[head]]-delta,cost=1ll*(2*n-i-1)*B,stp; if(Min<-p) stp=(-p-Min+1)/2,cost+=1ll*stp*A,tmp+=stp*2; cost+=1ll*(abs(tmp-Q)+1)/2*A; if(Min<-p) tmp-=stp*2; if(ans==-1||cost<ans) ans=cost; } } printf("%lld",ans); }

更简洁的做法:

#include<bits/stdc++.h> using namespace std; template <typename T> void chmin(T &x,const T &y) { if(x>y)x=y; } #define rep(i,l,r) for(int i=l;i<=r;++i) const int N=1e6+5,inf=2e9; char s[N]; int a[N],mn_a[N],b[N]; int main() { int n,p,q,x,y; cin>>n>>p>>q>>x>>y; scanf("%s",s+1); rep(i,1,n)s[i]=s[i]=='-'?-1:1; rep(i,1,n)a[i]=a[i-1]+s[i]; rep(i,1,n)mn_a[i]=min(mn_a[i-1],a[i]); int d=(q-p-a[n])/2; int ans=inf; rep(i,1,n) { int n_mn=min(a[n]-a[n-i+1]+mn_a[n-i+1],b[i-1]); int now=max(0,(-p-n_mn+1)/2); chmin(ans,(i-1)*y+(now+abs(d-now))*x); b[i]=min(b[i-1]+s[n-i+1],0); } cout<<ans; }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530299.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(8)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示