CCPC-Wannafly Winter Camp Day4 Div1 - 咆咆咆哮 - [三分+贪心]

题目链接:https://zhixincode.com/contest/18/problem/I?problem_id=267

题目描述

输入描述

 

输出描述

一行一个整数表示答案。

样例输入 1

3
20 1
15 10
20 2

样例输出 1

60

题解:

首先肯定的是,这 $n$ 次选择必然是分为两段的,前一段全部是召唤,后一段全部是加攻。

然后我们只需要考虑,这两段的数目即可,然后我们假设这个函数和最后的总攻击力是一个单峰函数,就可以上三分。

那么接下来考虑在确定多少张牌召唤,多少张牌加攻的前提下,怎么安排顺序:

因为生物数目是确定的 $x$,所以我们可以知道一张牌它如果 $b \cdot x - a$ 越大,把它选成加攻击力就更赚,因此可以排个序后确定哪些牌是召唤、哪些牌是加攻,从而最终确定总攻击力。

最后的时间复杂度就是 $O(\log_{1.5}n \cdot n \cdot \log_{2} n)$。

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> P;
#define a(p) (p.first)
#define b(p) (p.second)
const int maxn=1e5+5;

int n,x;
P c[maxn];
inline bool cmp(const P& u,const P& v) {
    return b(u)*x-a(u)<b(v)*x-a(v);
}
ll check(int mid)
{
    x=mid, sort(c+1,c+n+1,cmp);
    ll res=0;
    for(int i=1;i<=n;i++) res+=(i<=x)?a(c[i]):b(c[i])*x;
    return res;
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    cin>>n;
    for(int i=1;i<=n;i++) cin>>a(c[i])>>b(c[i]);
    int l=0, r=n; ll ans=0;
    while(l<=r)
    {
        if(r-l<=10)
        {
            for(int i=l;i<=r;i++) ans=max(ans,check(i));
            break;
        }
        int lmid=l+(r-l)/3, rmid=l+(r-l)*2/3;
        ll lres=check(lmid), rres=check(rmid);
        if(lres<=rres) l=lmid;
        else r=rmid;
    }
    cout<<ans<<endl;
}

猜你喜欢

转载自www.cnblogs.com/dilthey/p/10407528.html