10月24日备战Noip2018模拟赛20(A组)
T1 Cz礼物
题目描述
有Ñ种物品,第I种物品的价格为六,每天最多购买XI个。
有米天,第我天c♂x有无线的钱,他会不停购买能买得起的最贵的物品(送给c♀x的礼物当然要挑贵一些)。你需要求出他每天会购买多少个物品。
输入格式
第一行两个整数N,M。接下来Ñ行每行两个整数v [I]中,x [i]中。接下来中号行每行一个整数W [i]中。
输出格式
米行每行一个整数,第I行表示第我天购买的物品数量。
输入样例
3 3
1 1
2 2
3 3
5
10
15
输出样例
2
4
6
数据范围
对于20%的数据,N,m≤1000。
对于另外40%的数据,X1 = 1。
对于100%的数据,N,m≤100000,1≤vi≤109,1≤xi≤10000,0≤wi≤10^ 18。
思路
二分 +暴力
首先按照礼物的价值降序排列,因为c♂x非常喜欢c♀x,要尽量给c♀x买贵的东西。
然后用前缀和预先处理买下全部前我种物品要花费的前,以及前我种物品的数量
就然后可以愉快的二分了
1.二分查找出最多可以买第我件到第Ĵ件的全部物品;
2那么此时剩下的钱肯定是不能全部买下第就j + 1件物品的,那么可以只买一部分;。
3.二分查找出小于剩下的钱第ķ件物品的单价,重复1 .;
时间复杂度是
代码
#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;
}