题意: 给个数组,给个花费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;
}