bzoj 1122: [POI2008]账本BBB(优先队列+贪心)

版权声明:非游戏开发类文章可以随意转载,游戏开发类文章不可转载,除此之外博客中所有代码都并非项目中的实际代码,仅供学习和参考 https://blog.csdn.net/Jaihk662/article/details/79141070

1122: [POI2008]账本BBB

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 517  Solved: 248
[Submit][Status][Discuss]

Description

一个长度为n的记账单,+表示存¥1,-表示取¥1。现在发现记账单有问题。一开始本来已经存了¥p,并且知道最后账户上还有¥q。你要把记账单修改正确,使得 1:账户永远不会出现负数; 2:最后账户上还有¥q。你有2种操作: 1:对某一位取反,耗时x; 2:把最后一位移到第一位,耗时y。

Input

The first line contains 5 integers n, p, q, x and y (1 n 1000000, 0 p;q 1000000, 1 x;y 1000), separated by single spaces and denoting respectively: the number of transactions done by Byteasar, initial and final account balance and the number of seconds needed to perform a single turn (change of sign) and move of transaction to the beginning. The second line contains a sequence of n signs (each a plus or a minus), with no spaces in-between. 1 ≤ n ≤ 1000000, 0 ≤ p ,q ≤ 1000000, 1 ≤x,y ≤ 1000)

Output

修改消耗的时间

Sample Input

9 2 3 2 1
---++++++

Sample Output

3


暴力枚举操作2,然后对于每种情况算一下操作1需要多少次求个最小值

枚举操作2相当于就是把序列当成一个环,然后枚举起点

主要在如何求操作1要多少次

首先算一下到底需要多少个'+'和多少个'-',如果'-'少了就把最后面的若干个'+'改掉,

如果'+'少了就把最前面的如干个'-'改掉

之后再看会不会出现p+前缀和为负的情况,这里需要用优先队列先求出每个起点的最小前缀和

最小前缀和知道后,如果为负就需要将前面的'+'改成'-',后面的'-'改成'+'

OK,最后求出最小值

#include<stdio.h>
#include<queue>
#include<algorithm>
using namespace std;
#define LL long long
deque<int> Q;
char str[1000005];
LL a[2000005], b[2000005], sum[2000005];
int main(void)
{
	LL n, p, q, x, y, i, ans, now;
	scanf("%lld%lld%lld%lld%lld%s", &n, &p, &q, &x, &y, str+1);
	for(i=1;i<=n;i++)
		a[i] = str[i]=='+'?1:-1;
	for(i=n+1;i<=n*2;i++)
		a[i] = a[i-n];
	for(i=n*2;i>=1;i--)
		sum[i] = sum[i+1]+a[i];
	n *= 2;
	for(i=n;i>=1;i--)
	{
		if(i<=n/2)
			b[i] = sum[i]-sum[Q.back()];
		while(Q.empty()==0 && sum[Q.front()]<=sum[i])
			Q.pop_front();
		Q.push_front(i);
		while(Q.back()>=i+n/2)
			Q.pop_back();
	}
	ans = 214748364721474847ll;
	n /= 2;
	for(i=1;i<=n;i++)
	{
		now = y*((n-i+1)%n);
		if(p+sum[n+1]>=q)
			now += (p+sum[n+1]-q)/2*x;
		else
		{
			now += (q-p-sum[n+1])/2*x;
			b[i] += (q-p-sum[n+1]);
		}
		if(p+b[i]<0)
			now -= (p+b[i]-1)/2*2*x;
		ans = min(ans, now);
	}
	printf("%lld\n", ans);
	return 0;
}
/*
15 0 1 2 3
+--++---++--+++
15 5 0 1 1000
----------+++++
*/


没有更多推荐了,返回首页