10月24日备战Noip2018模拟赛20 (A组) T1 Cz 礼物

版权声明:本文为博主原创文章,转载请标明出处 https://blog.csdn.net/MOMING_V/article/details/83343893

10月24日备战Noip2018模拟赛20 (A组)

T1 Cz 礼物

题目描述

有n种物品,第i种物品的价格为vi,每天最多购买xi个。

有m天,第i天c♂x有wi的钱,他会不停购买能买得起的最贵的物品(送给c♀x的礼物当然要挑贵一些)。你需要求出他每天会购买多少个物品。

输入格式

第一行两个整数n,m。接下来n行每行两个整数v[i],x[i]。接下来m行每行一个整数w[i]。

输出格式

m行每行一个整数,第i行表示第i天购买的物品数量。

输入样例

3 3
1 1
2 2
3 3
5
10
15

输出样例

2
4
6

数据范围

对于20%的数据,n,m≤1000。

对于另外40%的数据,xi=1。

对于100%的数据,n,m≤100000,1≤vi≤109,1≤xi≤10000,0≤wi≤10^18。


思路

二分+暴力

首先按照礼物的价值降序排列,因为c♂x非常喜欢c♀x, 要尽量给c♀x买贵的东西。

然后用前缀和预先处理买下全部前i种物品要花费的前,以及前i种物品的数量

然后就可以愉快的二分了

1.二分查找出最多可以买第i件到第j件的全部物品;

2那么此时剩下的钱肯定是不能全部买下第就j + 1件物品的,那么可以只买一部分;.

3.二分查找出小于剩下的钱第k件物品的单价,重复1.;

时间复杂度是\Theta (nlog vlog n)

代码

#include <iostream>
#include <cstdio>
#include <cctype>
#include <algorithm>
#include <cstring>

using namespace std;

const int MAXN = 1e5 + 5;

struct Node{
	int cost;
	int amount;
}a[MAXN];

int n, m, u, v, tot;
int preNum[MAXN];
long long money;
long long preSum[MAXN];

inline long long read ();
inline bool cmp (const Node &A, const Node & B);
inline int lowerBoundDifference (int l, int r, long long x);
inline int lowerBound (int l, int r, int x);

int main ()
{
	//freopen ("cz.in", "r", stdin);
	//freopen ("cz.out", "w", stdout);
	
	n = read (), m = read ();
	for (register int i = 1; i <= n; i ++){
		a[i].cost = read (), a[i].amount = read ();
	}
	sort (a + 1, a + 1 + n, cmp);
	//for (int i = 1; i <= n; i ++) printf ("\t%d\n", a[i].cost);
	memset (preSum, 0, sizeof (preSum));
	memset (preNum, 0, sizeof (preNum));
	for (int i = 1; i <= n; i ++){
		preSum[i] = preSum[i - 1] + 1ll * a[i].cost * a[i].amount;
		preNum[i] = preNum[i - 1] + a[i].amount;
		//printf ("preSum[%d] = %d, preNum[%d] = %d\n", i, preSum[i], i, preNum[i]);
	}
	while (m --){
		money = read ();
		tot = 0;
		v = 1;
		while (v <= n){
			u = lowerBoundDifference (v, n, money);
			//printf ("u = %d\n", u);
			tot += preNum[u] - preNum[v - 1];
			money -= preSum[u] - preSum[v - 1];
			//printf ("tot = %d, money = %d\n", tot, money);
			v = u + 1;
			//printf ("v = %d\n", v);
			if (v > n) break;
			tot += money / a[v].cost;
			money %= a[v].cost;
			//printf ("tot = %d, money = %d\n", tot, money);
			v = lowerBound (v + 1, n, money);
			//printf ("v = %d\n", v);
		}
		printf ("%d\n", tot);
	}
	//fclose (stdin);
	//fclose (stdout);
	return 0;
}

inline long long read ()
{
	char ch = getchar ();
	int f = 1;
	while (!isdigit (ch)){
		if (ch == '-') f = -1;
		ch = getchar ();
	}
	long long x = 0;
	while (isdigit (ch)){
		x = x * 10 + ch - '0';
		ch = getchar ();
	}
	return x * f;
}
inline bool cmp (const Node &A, const Node &B)
{
	return A.cost > B.cost;
}

inline int lowerBoundDifference (int l, int r, long long x)
{
	int mid;
	int left = l;
	int right = r;
	while (left <= right){
		mid = (right - left) / 2 + left;
		if (preSum[mid] - preSum[l - 1] <= x) left = mid + 1;
		else right = mid - 1;
	}
	return right;
}
inline int lowerBound (int l, int r, int x)
{
	int mid;
	int left = l;
	int right = r;
	while (left <= right){
		mid = (right - left) / 2 + left;
		if (a[mid].cost <= x) right = mid - 1;
		else left = mid + 1;
	}
	return left;
}

猜你喜欢

转载自blog.csdn.net/MOMING_V/article/details/83343893
今日推荐