cf1251 E2. Voting (Hard Version)

Link

Link

Solution

首先和 e a s y   v e r s i o n easy\ version easy version一样,先按照 m i m_i mi排序

现在假设我已经知道了我要贿赂哪些人,现在我把整个过程看作如下:

先把所有的我要贿赂的人都给贿赂了,然后就开始从前往后引发雪崩式反应

如果我贿赂的人不够的话,那么就会出现这种情况: m m m值为 1... x − 1 1...x-1 1...x1的人都已经投我了,但是 m m m值为 x x x还没有投我

p r e f x pref_x prefx表示 m m m值小于 x x x的人数, c n t x cnt_x cntx表示 m m m值大于等于 x x x的人当中我贿赂了多少人

那么如果 p r e f x + c n t x < x pref_x+cnt_x<x prefx+cntx<x,对前面的都成立,而到了这里就不成立了,那么就说明卡在这里了,那我就必须提高 p r e f x + c n t x pref_x+cnt_x prefx+cntx的值,而 p r e f x pref_x prefx的值是固定的,所以我只好提高 c n t x cnt_x cntx的值,也就是选一些人( m m m值等于 x x x的)进行贿赂,显然我必须恰好贿赂 x − ( p r e f x + c n t x ) x-(pref_x+cnt_x) x(prefx+cntx)个人才行。

从上述分析可以看出,无论 x x x的前方怎么选, x x x的后方一共选多少人是一定的

但是在 x x x这里具体要选谁,还受到 x + 1 , x + 2 , . . . x+1,x+2,... x+1,x+2,...选择谁的影响

但是有一个事情是确定的,就是 m i = n − 1 m_i=n-1 mi=n1的那些人里面要选几个。如果 ( n − 1 ) − p r e f n − 1 > 0 (n-1)-pref_{n-1}>0 (n1)prefn1>0,那我就得在 m i = n − 1 m_i=n-1 mi=n1的这群人当中选出 ( n − 1 ) − p r e f ( n − 1 ) (n-1)-pref_(n-1) (n1)pref(n1)个进行贿赂。显然我要选最便宜的几个,而且可以理解的是,最优方案中肯定要选这几个人,因为不管前面怎么选,我都一定要在 m i = n − 1 m_i=n-1 mi=n1的人中选择 ( n − 1 ) − p r e f n − 1 (n-1)-pref_{n-1} (n1)prefn1个人进行贿赂。

然后对于 m i = n − 2 m_i=n-2 mi=n2的人来说,假设 ( n − 2 ) − p r e f n − 2 > 0 (n-2)-pref_{n-2}>0 (n2)prefn2>0,那么我就在上一轮剩下的人再加上 m i = n − 2 m_i=n-2 mi=n2的这些人中贪心取最便宜的,可以理解的是,最优方案中也一定包含这些人,理由和上面一样。

依次类推

Code

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define iinf 0x3f3f3f3f
#define linf (1ll<<60)
#define eps 1e-8
#define maxn 1000010
#define maxe 1000010
#define cl(x) memset(x,0,sizeof(x))
#define rep(i,a,b) for(i=a;i<=b;i++)
#define drep(i,a,b) for(i=a;i>=b;i--)
#define em(x) emplace(x)
#define emb(x) emplace_back(x)
#define emf(x) emplace_front(x)
#define fi first
#define se second
#define de(x) cerr<<#x<<" = "<<x<<endl
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
ll read(ll x=0)
{
    ll c, f(1);
    for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
    for(;isdigit(c);c=getchar())x=x*10+c-0x30;
    return f*x;
}
vector<ll> v[maxn];
int main()
{
    ll T=read();
    while(T--)
    {
        ll n=read(), i;
        rep(i,0,n-1)v[i].clear();
        rep(i,1,n)
        {
            ll m=read(), p=read();
            v[m].emb(p);
        }
        ll cnt=0, ans=0, pref=n;
        multiset<ll> mts;
        drep(i,n-1,0)
        {
            pref -= v[i].size();
            for(auto x:v[i])mts.em(x);
            ll need = i-pref-cnt;
            while(need>0)
            {
                ans += *mts.begin();
                mts.erase(mts.begin());
                need--;
                cnt++;
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值