B. Balanced Diet(前缀数组+贪心)

Gym_102220_B_Balanced Diet

B. Balanced Diet
time limit per test:2 seconds
memory limit per test:512 megabytes
input:standard input
output:standard output

Taylor is wandering in a milk candy store. The store has m types of sweets and there are n sweets in the store. The i-th sweet has the value of ai, and it is of type bi.

Taylor is planning to buy some sweets in the store, each sweet can be bought at most once. He will buy at least one sweet. Taylor knows that a balanced diet is important, the value of a sweet set is measured as S/C, where S denotes the sum of ai and C denotes the maximum number of occurrences among all types of sweets.

Assume Taylor selects pi sweets of type i, it is not welcomed if 1≤pi

Please write a program to help Taylor find the sweet set with maximum value.

Input
The first line of the input contains an integer T(1≤T≤1000), denoting the number of test cases.

In each test case, there are two integers n,m(1≤n,m≤100000) in the first line, denoting the number of sweets and types.

In the second line, there are m integers l1,l2,…,lm(1≤li≤n).

For the next n lines, each line contains two integers ai,bi(1≤ai≤108,1≤bi≤m), denoting each sweet.

It is guaranteed that ∑n≤106 and ∑m≤106, and there always exists a valid sweet set.

Output
For each test case, print a single line of format u/v, denoting the maximum value uv. Note that you should guarantee that gcd(u,v)=1.

Example
Input

2
2 1
2
7 1
2 1
3 2
1 2
2 1
5 2
3 2

Output

9/2
5/1

题目大意

自己好菜呀!这个题意读了好久才明白。先是给你一个数 T 有T组数据!
每组数据 给了 N和M表示有M种类型的糖果,这些糖果一共N个。
接下了是 M 组数据,表示如果你选第 i 中糖果,那么你最少选 Li (你也可以不选),
再接下来就是 N 行数据,每一行 ai 和 bi 表示这个糖果属于 bi 这个种类的,它的价值是ai。
最后让你输出你挑选的糖果的总价值除以 你取得糖果中数量最多的那种糖果的数量,然后化成最简分数,
比如说 第 1 种你取了 2 个,第 2 中你取了 4 个,第三种你取了 1 个,那么分母就是 4 了。

解题思路

相比读题的苦苦挣扎,解题就好受多了,既然我们要选出的分数最大,那么我们就可以直接暴力的去比较,从最多选一个,然后两个,这样我们遍历一遍就好了,从前向后开始遍历的时候,我们可以提前预处理一下,将每种没类型的的糖果的价值从大到小进行排序,然后遍历到几选的时候就可以直接选了前几个就行了,用一个vector数组,进行储存选几的时候sum和是多少。(注意我们不能直接找出最多要选的数量,然后每种都选前 相应 的数量的价值数,因为可能这种类型的糖果我们可以不选)说的有点复杂还是直接看代码吧!
代码已经修改,感谢 Stephen_Zhao0 的hack样例与指导!

代码

#include
using namespace std;
typedef long long ll;
vector<ll>ve[100009],vec[100009];
int a[100009];

bool cmp(int x,int y)
{
  return x>y;
}

int main()
{
  ios::sync_with_stdio(0);
  int x,y,t,n,m;
  cin>>t;
  while(t--)
  {
  	cin>>n>>m;
  	for(int i=1;i<=m;i++) cin>>a[i];//第i种类型如果要取得话最少取多少 
  	for(int i=0;i<n;i++) cin>>x>>y,ve[y].push_back(x);
  	for(int i=1;i<=m;i++)
  	{
  		sort(ve[i].begin(),ve[i].end(),cmp);//排序 
  		ll sum=0;
  		for(int j=0;j<ve[i].size();j++)
  		{
  			//构建前缀数组 因为你如果选的话,最少选 a【i】个数,
  			//	所以让前a【i】个价值都放到选a【i】 这种情况,后面的就放入对应的位置 
  			if(j<a[i])
   			sum+=ve[i][j];
   		if(j>=a[i]){
   			vec[j+1].push_back(ve[i][j]);
   		}	
  			if(j+1==a[i]){
  				vec[j+1].push_back(sum);
   		}
  		}										
  		ve[i].clear();
  	}
  	ll ms=0,mc=1,ns=0,nc;//注意这里要用long long 不然第 2 组会爆 int 
  	for(int i=1;i<=n;i++)
  	{
  		nc=i;
  		for(int j=0;j<vec[i].size();j++){
  			ns+=vec[i][j];//累计前 i 项的和 
  		}
  		if(ms*nc<ns*mc)  ms=ns,mc=nc;//取最大的一组解 
  		vec[i].clear();
  	}
  	ll k=__gcd(ms,mc);
  	cout<<ms/k<<"/"<<mc/k<<endl;
  }
  return 0;
}

你可能感兴趣的:(CF,贪心,B.,Balanced,Diet(前缀数组+贪心))