Balanced Diet(前缀数组)

题目链接:codeforces.com/gym/102220/problem/B

Balanced Diet

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≤10e8,1≤bi≤m), denoting each sweet.
It is guaranteed that ∑n≤10e6
and ∑m≤10e6, 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 u/v. 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

题意:给出共m种类型的n颗糖果,每颗糖果有自己的价值和属于一种类型,让你选出一些糖果(每类糖果要么不选,要么至少选li个),求最大的S/C,S是选出糖果的价值总和,C是选出糖果构成所有类型中个数最大值,比如你选了1类糖果3个,2类糖果6个,3类糖果2个,这时C为6。

思路:枚举分母C,C只能是li。用vector数组来保存每类糖果,在每类糖果中选一定数目时,价值越大越好,所以对每个vector排降序,排序后将vector做成前缀和数组,再将每类糖果按li排序,当我们枚举li时,前面的lk<=li,前面的糖果可取,后面的lj>li,不可取。分析题目的数据量,不同的li最多有n^(1/2)个,li:1,2,3,4,5…,所有的li加起来小于等于n。

例如:
10 9 8 7 6 6 5 4 3
12 8 7 6 4 2 2 1 1 1
12 8 7 6 4 2 2 1 1 1
13 8 7 6 4 3 2 1 1 1 1 1 1
一行代表一类糖的价值,加粗代表li,按li排好序,2<6<6<10。

枚举分母C:
C取2、3、4、5
C取6、7、8、9
C取10、11、12、13

可以发现:
C取2大于或等于取3、4、5
C取6大于或等于取7、8、9
C取10大于或等于取11、12、13
对于一个递减的数列a1、a2、a3…,前i个数的平均大于等于前j个数的平均(i

实现代码:

#include 
#include
#include
#include
#include
#include
#include
using namespace std;

typedef long long ll;

const int INF=0x3f3f3f3f;
const int MAX_N=100000+5;

int n,m;
vector<ll> sum[MAX_N+1];//,每类糖的前缀和数组
int L[MAX_N+1];
int rak[MAX_N+1];//间接排序

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

bool cmp2(int i,int j){
    return L[i]<L[j];
}

ll gcd(ll a,ll b){
    if(b==0)return a;
    return gcd(b,a%b);
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)scanf("%d",&L[i]);
        int a,b;
        for(int i=1;i<=m;i++){
            sum[i].push_back(0);
        }
        for(int i=1;i<=n;i++){
            scanf("%d%d",&a,&b);
            sum[b].push_back(a);
        }
        
        for(int i=1;i<=m;i++){
            sort(sum[i].begin()+1,sum[i].end(),cmp);
            for(int j=1;j<sum[i].size();j++){//构造前缀和
                sum[i][j]+=sum[i][j-1];
            }
        }
        
        for(int i=1;i<=m;i++)rak[i]=i;
        sort(rak+1,rak+m+1,cmp2);//按L排序
        
        ll A=0,B=1;
        for(int ii=1;ii<=m;ii++){
            int si=L[rak[ii]];
            while(ii<=m&&L[rak[ii]]==si)ii++;//取不同的L枚举
            ii--;
            int i=rak[ii];
            ll ans=0;
            for(int jj=1;jj<=ii;jj++){
                int j=rak[jj];
                int k=min(L[i],(int)sum[j].size()-1);
                ans+=sum[j][k];
            }
            if(ans*B>A*L[i]){
                A=ans;B=L[i];
            }
        }
        
        ll gc=gcd(A,B);
        A/=gc;B/=gc;
        printf("%lld/%lld\n",A,B);
        
        for(int i=1;i<=m;i++){
            sum[i].clear();
        }
    }
    return 0;
}

你可能感兴趣的:(acm,acm)