补题记录-Codeforces Round #560 (Div. 3)-F2 Microtransactions (hard version)(二分+贪心)

题目链接[http://codeforces.com/contest/1165/problem/F2]
(Codeforces Round #560 (Div. 3))

Codeforces Round #560 (Div. 3)-F2 Microtransactions (hard version)

#98kai想进wf# 小菜鸡第一次写博客!!之前一直是在一个word文档上记录自己的刷题不会的题,但是发现真的好不方便,看到身边的大佬们都在用写博客的方式来“记忆化”,于是我也就开始写博客了!一般都会更新一些codeforces或者省赛,区域赛的题目。ok废话不多说,先看这道题。

题意:

							F2. Microtransactions (hard version)
								time limit per test3 seconds
							memory limit per test256 megabytes
									inputstandard input
									outputstandard output

The only difference between easy and hard versions is constraints.

Ivan plays a computer game that contains some microtransactions to make characters look cooler. Since Ivan wants his character to be really cool, he wants to use some of these microtransactions — and he won’t start playing until he gets all of them``.

Each day (during the morning) Ivan earns exactly one burle.

There are n types of microtransactions in the game. Each microtransaction costs 2 burles usually and 1 burle if it is on sale. Ivan has to order exactly ki microtransactions of the i-th type (he orders microtransactions during the evening).

Ivan can order any (possibly zero) number of microtransactions of any types during any day (of course, if he has enough money to do it). If the microtransaction he wants to order is on sale then he can buy it for 1 burle and otherwise he can buy it for 2 burles.

There are also m special offers in the game shop. The j-th offer (dj,tj) means that microtransactions of the tj-th type are on sale during the dj-th day.

Ivan wants to order all microtransactions as soon as possible. Your task is to calculate the minimum day when he can buy all microtransactions he want and actually start playing.

Input
The first line of the input contains two integers n and m (1≤n,m≤2⋅105) — the number of types of microtransactions and the number of special offers in the game shop.

The second line of the input contains n integers k1,k2,…,kn (0≤ki≤2⋅105), where ki is the number of copies of microtransaction of the i-th type Ivan has to order. It is guaranteed that sum of all ki is not less than 1 and not greater than 2⋅105.

The next m lines contain special offers. The j-th of these lines contains the j-th special offer. It is given as a pair of integers (dj,tj) (1≤dj≤2⋅105,1≤tj≤n) and means that microtransactions of the tj-th type are on sale during the dj-th day.

Output
Print one integer — the minimum day when Ivan can order all microtransactions he wants and actually start playing.

Examples
inputCopy
5 6
1 2 0 2 0
2 4
3 3
1 5
1 2
1 5
2 3
outputCopy
8
inputCopy
5 3
4 2 1 3 2
3 5
4 2
2 5
outputCopy
20
题意其实很简单,就是给你n中物品,购买每个物品需要消耗2元。每个物品都有一个需求量。然后每天(不一定)都有一些折扣,如果在当天购买有折扣的物品需要1元钱。每天你的钱数会增加1元(现增加,后购买),求至少多少天能把所有需求的物品买完。

思路:

我做的时候,乍一看以为是一个dp,因为每天都有选择买和不买两个状态,看到数据量2e5以后,就想最多nlogn,dp好像出不来,当时比赛剩余时间已经不多,加上已经凌晨一点,就放弃挣扎了。不过第二天起来,想一想二分答案,再配上贪心,其实挺简单。就是二分答案,左边界l是1,右边界r是sum*2(sum是所有物品的需求量之和)(这里注意,千万不能是sum,因为每个物品是2元。),然后每次判断在mid天之前能否买完,判断的时候用贪心的思想,先维护一个数组last[],表示第i个物品在mid天内最后一次又折扣是在哪一天,然后比那里每一个折扣(按照d从小到大排序),如果目前的折扣物品有着扣得最后一天就是目前的天数,就能买多少买多少就行了(当然,不能超过上限,就是不超过需求量)。如果所有的折扣遍历完,如果剩下的钱能把所有剩余物品按照2元每个买完,那么就return true,不然就false。维护一个答案ans,ans=min(ans,mid),最后输出ans就行。

下面是代码:

// #include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<ostream>
#include<cstring>
#include<string.h>
#include<string>
#include<cstdio>
#include<cctype>
#include<vector>
#include<cmath>
#include<queue>
#include<set>
#include<stack>
#include<map>
#include<cstdlib>
#include<time.h>
#include<bitset>
#define pb push_back
#define _fileout freopen("out.txt","w",stdout)
#define _filein freopen("in.txt","r",stdin)
#define test(i) printf("ok%d\n",i)
using namespace std;
typedef double db;
typedef long long ll;
const double PI = acos(-1.0);
const ll MOD=1e9+7;
const ll MAXN=2e5+10;
const int INF=0x3f3f3f3f;
const ll ll_INF=9223372036854775807;
ll qm(ll a,ll b){ll ret = 1;while(b){if (b&1)ret=ret*a%MOD;a=a*a%MOD;b>>=1;}return ret;}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){return (a*b)/gcd(a,b);}
struct state
{
	int d,t;
	bool operator <(const state &a)const
	{
		return d<a.d;
	}
}s[MAXN];
int n,m;
int sum;
int k[MAXN];
int last[MAXN];
int a[MAXN];//目前的状态下,第i个物品已经买了多少个了
bool slove(int x)
{
	memset(a,0,sizeof(a));
	memset(last,0,sizeof(last));
	for(int i=1;i<=m;i++)
	{
		if(s[i].d>x)break;
		last[s[i].t]=max(last[s[i].t],s[i].d);
	}
	int money=0;
	int cnt=0;
	for(int i=1;i<=m;i++)
	{
		if(s[i].d>x)break;
		money+=(s[i].d-s[i-1].d);	
		// printf("i=%d money=%d\n",i,money);
		if(last[s[i].t]==s[i].d&&a[s[i].t]<k[s[i].t])
		{
			int mid=min(money,k[s[i].t]-a[s[i].t]);
			// printf("mid=%d\n",mid);
			money-=mid;
			cnt+=mid;
			a[s[i].t]+=mid;
		}
	}
	if(2*sum-cnt<=x)return true;
	return false;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&k[i]);
		sum+=k[i];
	}
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&s[i].d,&s[i].t);
	}
	sort(s+1,s+1+m);
	int ans=sum*2;
	int l=1;
	int r=sum*2;
	int mid;
	while(r>=l)
	{
		mid=(l+r)/2;
		if(slove(mid)){ans=min(ans,mid);r=mid-1;}
		else l=mid+1;
	}
	printf("%d\n",ans);
	return 0;
}

第一次写博客,感触:写博客真的好麻烦!!!

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值