专栏文章

怎么都写的这么复杂。

P3470题解参与者 12已保存评论 13

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
13 条
当前快照
1 份
快照标识符
@mindv2aa
此快照首次捕获于
2025/12/02 00:48
3 个月前
此快照最后确认于
2025/12/02 00:48
3 个月前
查看原文
模拟赛切了,来发儿子点的题解。

sol

手玩一下这个循环右移操作,记这个 +11+1-1 的前缀和数组为 ss
记这个 ss 数组里的值的最小值mnmn,你考虑一次右移对这个 mnmn 的影响是啥。
手玩发现右移一个 ++给所有原来是 - 的位置 +2+2,右移一个 -给所有原来是 ++ 的位置 2-2
那么这个时候你就发现,右移一个加号给一个减号的位置 +2+2,那么最小值是不是就是 +2+2
实际上是不对的,因为一个最小值的出现一定是 ++- 的一个交界处,实际上应该是最小值 +1+1
同理可得如果右移的是 - 那么应该是最小值 1-1
那么这个时候就没啥难度了,你就可以枚举你用几次右移操作,然后你就知道你的最小值和总共的和了。
总共的和肯定要等于 qq
sn<qs_n < q 根据经典贪心暴力选最前面的 - 改,算一下它对最小值的影响。
sn>qs_n > q 其实可以不用管,你直接把末尾的加号给改成 - 一定不会使最小值变为负的。
然后每次对最小值 +2+22x2x 的代价,这个也好 O(1)O(1) 算。
做完了,复杂度 O(n)O(n)
但是这个地方有一点要提,如果这个 mnmn 是在 sns_n 的,你循环右移是不会将其 1-1 的。
但是这个对于我们答案完全没有影响,因为 sns_n 必须要等于 qq
代码细节有点多,我还是给一下:
CPP
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
int n,p,q,x,y,m,ans=INT_MAX,sum,a[1000001],mxl,mxr,mn=INT_MAX;
string s;
signed main(){
//	freopen("book.in","r",stdin);
//	freopen("book.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n>>p>>q>>x>>y>>s;
//	assert(s.size()==n);
	s=" "+s;
	a[0]=p;
	for(int i=1;i<=n;i++){
		a[i]=a[i-1]+(s[i]=='+'?1:-1);
//		cout<<a[i]<<" ";
		if(i!=n) mn=min(mn,a[i]);
	}
//	cout<<'\n';
	int l=n,sm=a[n];
//	assert(!((q-sm)&1));
	for(int i=1;i<=n;i++){
		int vl=mn,val=(i-1)*y;
		if(sm<q) val+=(q-sm)/2*x,vl+=(q-sm);//改最前面的减号。 
		else if(sm>q)val+=(sm-q)/2*x;//改最后面的正号。
		if(vl>=0) ans=min(ans,val);
		else val+=(-vl+1)/2*2*x,ans=min(ans,val);
		if(s[l]=='-') mn--;
		else if(s[l]=='+')mn++;
		l--; 
	}
	cout<<ans;
	return 0;
}
/*
首先肯定要通过改位去把整个串的和给改为 p。 
9 0 3 4 1
---+-++-- 

*/

评论

13 条评论,欢迎与作者交流。

正在加载评论...