题目链接:Balanced Diet - Gym 102220B - Virtual Judge (vjudge.net)
泰勒在一家牛奶糖果店闲逛。这家商店有m种糖果,店里有n颗糖果。第i个颗的价值为ai,类型为bi。泰勒打算在店里买一些糖果,第i种糖果他至少买li个。Taylor知道均衡的饮食是很重要的,一个甜食集合的值被测量为S/C,其中S表示所选糖果价值的和,C表示在所有类型的甜食中同类型出现的最大次数。请编写一个程序帮助泰勒找到值最大的甜蜜集。
思路:我们需要开一个二维vector去存储每种类型糖果的每颗的价值,然后从大到小排,通过计算前缀和去实现选择该类型糖果多少颗的最大化(用g[ i ][ j ]代替),同时记录一下所有类型中最多的那种的数量ma。然后对结构体L中的LL进行从小到大的排序。
对于这个S/C这个式子最大的话要遍历每个S也就是选择1到ma的糖果数量
然后分母是所有的g[ i ][ j ]的加和(i为糖果的类型,j为选择糖果的数量,j要大于了L[ i ].LL,并且如果j > g[ i ].size()(也就是该类型糖果的数量),则 j = g[ i ].size()),然后计算每个S/C然后记录它最大时的S和C。最后输出最简形式。
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 10;
int n,m,x,y;
int a[N],b[N];
vector<int>g[N];
map<int,int>mp,mk;
struct node{
int ll,id;//ll为该类型至少买多少颗,id为糖果类型
}l[N];
bool cmp(node a,node b){
if(a.ll!=b.ll)
return a.ll<b.ll;
return a.id<b.id;
}
void solve () {
cin>>n>>m;//输入糖果颗数n,糖果类型m
double md=0;
mp.clear();//清空mp容器
for(int i=1;i<=m;i++)cin>>l[i].ll,l[i].id=i,g[i].clear();//输入第i类型至少买多少颗,同时清空g容器
for(int i=1;i<=n;i++){
cin>>a[i]>>b[i];//输入糖果价值以及对应的类型
g[b[i]].push_back(a[i]);//将该价值放入对应类型的容器内
}
int ma=0;
for(int i=1;i<=m;i++){
sort(g[i].begin(),g[i].end(),greater<int>());//将同类型糖果价值从小到大排。
for(int j=1;j<g[i].size();j++){
g[i][j]+=g[i][j-1];//计算前缀和,使g[i][j]意思变为第i类型选择j颗糖果的最大价值
}
if(g[i].size()>ma)ma=g[i].size();//记录所有类型中同类型糖果最大数量
}
sort(l+1,l+m+1,cmp);int k=1;//将结构体按照至少买多少颗糖果从小到大排
for(int i=1;i<=ma;i++){//遍历买1颗到买ma颗
for(int j=1;j<=m;j++){//计算买i颗时最大价值
if(l[j].ll>i){//如果没有到达买该糖果的最小需求则停止循环。
break;
}
int d=g[l[j].id].size();
if(min(i,d)-1<0)continue;//防止re因为有糖果有这个类型但没有数量。
mp[i]+=g[l[j].id][min(i,d)-1];//min(i,d)是如果所选的i颗大于所有的数量就选所有的糖果
}
if(md<1.0*mp[i]/i){//求最大的S/C
md=1.0*mp[i]/i;x=mp[i],y=i;//记录此时的S和C
}
}
int c=gcd(x,y);//最大公因数
cout<<x/c<<"/"<<y/c<<endl;//化为最简形式
}
signed main () {
int T = 1;
std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>T;
while (T --) solve ();
return 0;
}