2018计蒜之道 第一场 A

题目链接

题意: 给个数组,给个花费p,给个总钱数s。每次让数组任一元素减一,并花费p。要求在总花费小于s的情况下,使数组的最大元素最小,然后输出这个最小值。

思路:我都不知道为什么一开始思路是暴力,一波优先队列交上去,交完马上想到 s <= 1e18,暴个鸡毛啊,果不其然TLE……然后看数组长度只有2e4,ok,先用 s/p 算出可以操作的次数,再把数组排序去重,记录每个值的个数,然后从最大的往下减,一个一个的减肯定是不行的,那么就相邻两个减,得到差值,然后乘上个数就是降一级需要的次数

如果这个数小于剩下的操作数,那就直接把下一个的个数加上当前这个值的个数

如果这个数等于剩下的操作数,那最后的结果就是下一个数,记录 and break

如果这个数大于剩下的操作数,肯定就是减不完,当前数 - 剩下的操作数 / 当前值的个数,记录 and break

PS:总费用会爆掉int,所以用long long

#include<algorithm>
#include<typeinfo>
#include<stdlib.h>
#include<string.h>
#include<iostream>
#include<iomanip>
#include<stdio.h>
#include<math.h>
#include<string>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
#define pi acos(-1)
ll gcd(ll x, ll y) { return x ? gcd(y%x, x) : y; }
ll lcm(ll x, ll y) { return x * y / gcd(x, y); }

int n, val[20005], x, len;
ll s, p;

int main() {
	ios::sync_with_stdio(false);
	cout << fixed << setprecision(6);

	while (~scanf("%d", &n)) {
		map<int, int>mp;
		set<int>st;
		st.insert(1);
		for (int a = 0; a < n; a++)
			scanf("%d", &x), st.insert(x), mp[x]++;
		scanf("%lld%lld", &p, &s);
		len = st.size();
		for (auto &a : st)
			val[--len] = a;
		len = st.size();
		int num = s / p, ans;
		for (int a = 0; a < len; a++) {
			if (val[a] == 1) {
				ans = 1;
				break;
			}
			x = val[a] - val[a + 1];
			if (num > x*mp[val[a]])
				mp[val[a + 1]] += mp[val[a]], num -= x * mp[val[a]];
			else if (num == x * mp[val[a]]) {
				ans = val[a + 1];
				break;
			}
			else {
				int b = num / mp[val[a]];
				ans = val[a] - b;
				break;
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/icliuli/article/details/80307696