【牛客网】埃森哲杯第十六届上海大学程序设计联赛春季赛暨上海高校金马五校赛 G.小Y做比赛

题目链接

(贪心+双指针模拟2个优先队列)

题意:已知一个人一定可以AK一套题目,要求他的最小总罚时(从比赛开始到做出这题的时间为该题的罚时)

给出一个n,表示一共有n道题,随后n行a[i]和b[i](表示第i道题需要a[i]的读题时间和b[i]的敲代码时间,保证ac)并且他有个习惯,当剩余题数大于2题时会先读多一题,然后取2题敲代码时间最短的先敲(只有一题自然只能做它)

题解:因为前面花费的时间会对后面影响很大,所以肯定是容易的题即ac题目耗费时间少的先完成,又由于题目有而外的要求(读2题再写)那么我读的第一题必然是读题时间最短的,然后第一道ac的题目可以是读下一题然后ac第一道题,也可以是ac了第二题再进行其他判断(保证每次ac题目罚时最少)

所有我们可以这么做:

       第一步: x[]数组保存a的时间,xy[]数组保存a+b的时间,对他们都进行升序排序取(并且要记录下标)

       第二步:取最小读题时间的x[q=0]数组第一个数对应的题号(默认先读他了)然后用一个b0保存他的b

       第三步:j接下来还需要ac多n-1个题,取题通过比较xy[p].v的值即a2+b2 和x[q].v+b0的值a2+b1

                                       (这里1指前一题,2指后一题,若是后者小b0也需要变为b2)

       最后把b0也加上就得到最后一题的ac时间。(代码中t是时间轴,因此每次ac题目ans+=t】

代码如下:

#include<iostream>  
#include<cstring>  
#include<string>  
#include<cstdio>  
#include<cmath>  
#include<vector>  
#include<queue>  
#include<map>  
#include<algorithm>  
using namespace std;
#define inf 0x3f3f3f3f3f3f  
#define ll long long  
const int maxn = 1e5 + 500;
struct node
{
	ll v;
	int index;
}xy[maxn], x[maxn];
ll b[maxn];
bool vis[maxn];
bool cmp(node xx, node yy)
{
	return xx.v < yy.v;
}
int main()
{
	int n;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		scanf("%lld%lld", &x[i].v, &b[i]);
		xy[i].v = x[i].v + b[i];
		xy[i].index = i; x[i].index = i;
	}
	sort(xy, xy + n, cmp);
	sort(x, x + n, cmp);
	int p = 0, q = 0;//2个指针分别是记录xy[],x[]遍历到的位置  
	ll t = x[q].v, b0 = b[x[q].index]; vis[x[q++].index] = true; //取第一组数据  
	int cnt = 1;
	ll ans = 0;
	while (cnt++ != n)
	{
		while (vis[xy[p].index]) p++;
		while (vis[x[q].index]) q++;
		if (xy[p].v <= x[q].v + b0)
		{
			vis[xy[p].index] = true;
			t += xy[p++].v;
			ans += t;
		}
		else
		{
			vis[x[q].index] = true;
			t += x[q].v + b0;
			b0 = b[x[q++].index];
			ans += t;
		}
	}
	t += b0;
	ans += t;
	cout << ans << endl;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_41156591/article/details/80208141