13th - B : Balanced Diet
题目大意
要求你选糖果,首先给定m,n代表糖果最大可能种类数和给定的糖果总数,之后给定 m 个值(l1, l2, … lm),代表决定选某一种糖果时至少拿多少个,(可以不选),之后给定 n 个 ai 与 bi,代表每个糖果的价值与所属种类,要求使 S/C 最大 S代表拿取糖果的价值总和,C代表拿的糖果里,出现的最多的种类的糖果个数。
解题思路
首先我们先将每种糖果的取数下限排序,由于当最大值确定时,分母就确定了,为了使总值最大,其他种类的糖果就可以在不超过最大值的情况下尽可能的取最多,所以枚举C,之后只需要遍历每一种类,只要可以拿,就将该种类的糖果尽可能的往里装(最大价值优先),那么就可以得到每一种C时的最优解,比较这些值取最优即可。为了不超时,需要对其优化,不能简单遍历。
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<cmath>
#include<cstring>
#include<string>
#include<cstdio>
#include<stack>
using namespace std;
typedef unsigned long long ll;
typedef pair<int, int> PII;
const int mod = 1e9 + 7;
const int N = 1e5 + 100;
const int M = 1e6 + 10;
vector<int> G[N];
int used[N];//用于存储每类糖果已经有多少个被加进去了
int main(){
std::ios::sync_with_stdio(false);//关闭同步,防止因输入超时
int t;
cin >> t;
while(t--){
int n, m;
cin >> n >> m;
for (int i = 0; i <= m;i++){
G[i].clear();
used[i] = 0;
}
vector<PII> L;
for (int i = 1; i <= m;i++){
int l;
cin >> l;
L.push_back({l, i});
}
for (int i = 1; i <= n;i++){
int a, b;
cin >> a >> b;
G[b].push_back(a);
}
sort(L.begin(), L.end());
for (int i = 1; i <= m;i++){
sort(G[i].begin(), G[i].end());
reverse(G[i].begin(), G[i].end());
}
ll ansS = 0, ansC = 1;
ll S = 0, C = 1;
ll nowS = 0, nowC = 1;
//因为C每一次自增一,所以已经符合条件的只需要再加一个值即可,用一个标记存储,已经加入的所有值
ll vis = 0;//由于 li 排列好了,所以不需要每次遍历,每次C增加只需从不匹配的那个往后找就好
vector<int> p;
for (int i = 1; i <= n;i++){
for (vis; vis < L.size();vis++){
int tot = L[vis].first;
if(tot<=i){
p.push_back(L[vis].second);
//存储符合条件的种类
if(G[L[vis].second].size() >= i - 1){
for (int j = 0; j < i - 1;j++){
nowS += 1ll*G[L[vis].second][j];
}
used[L[vis].second] = i - 1;
//把该种类之前的加进去
}
else{
p.pop_back();//个数不满足弹出
}
}
else{
break;
}
}
for (int k = 0; k < p.size();k++){
int tot1 = p[k];
if(used[tot1]<G[tot1].size()){
used[tot1]++;
nowS +=1ll*G[tot1][used[tot1] - 1];
}
//若该类还有糖剩余,就往标记里加入
else{
if(k==p.size() - 1){
p.pop_back();
}
else{
p[k] = p[p.size() - 1];
k--;
p.pop_back();
}
//没有剩余就把这个种类弹出去,防止不必要的遍历
}
}
if(ansS*i>ansC*nowS){
continue;
}
else{
ansS = nowS;
ansC = i;
}//找最优解
}
int ggccdd = __gcd(ansS, ansC);
ansS /= ggccdd;
ansC /= ggccdd;
cout << ansS << '/' << ansC << endl;
}
return 0;
}