Codeforces Contest 457 C Elections —— 三分

This way

题意:

有n个人要投票,第i个人会投给第ai个人。你是第0个人,你需要收买一些人使得最终你的票数比任何人的票数都多。第i个人需要bi块钱去收买。

题解:

在cf上不能交的题目,拉到vjudge上就能交了,非常神奇。
一开始以为是二分最终有多少票,因为那时候觉得票数越少买的人就越少,那么花的钱就越少。但是不是这样的,有时候买的人数多一点范围就会更广一点,举个例子:
13
1 10000
1 10000
1 10000
2 10000
2 10000
2 10000
3 10000
3 10000
3 10000
4 1
5 1
6 1
7 1
当我二分到3的时候,我肯定要把1,2,3那里分别买最少的,需要花30000元,由于是合法的,因为3的时候必须买的最少人数<=3,什么叫最少买的人数,假设我二分到2,那么所有人数>=2的人我都需要使得他们<2,那么我就需要买6张票,但是6>=2,所以买两张票就胜利是不可能的。把所有人降低到你的人数以下的最少收买人数就叫最少买的人数。
显然二分是错的,那么怎么办,我们发现他有一个显然的性质,当你买的人数大到一定程度的时候,继续买一定花的钱更多。那么这就是一个类似 y = − x 2 y=-x^2 y=x2的曲线,那么就能用三分。
在三分的时候首先我们看看买这么多人是否可能,可能的话我们就做,我们用两种multiset记录信息:第一种是1e5个人,每个人那里收买的所有可能性,第二个是一个pair存的multiset,代表所有人投的票的信息,存的第一个数是收买这个人需要花的钱,第二个数是这个人投给了谁。
首先我们将所有人数>=x的人那里买,之后如果不够就从所有的人那里买,用vis记录已经买过的信息。
注意三分的退出条件是r>l+2,并且三分的话可能不会分到边界值的情况,所以最后要坐一下l和r的情况。

#include
using namespace std;
#define pa pair
const int N=1e5+5;
multisetst[N];
struct node
{
    int id,num;
    bool operator< (const node& a)const
    {
        return num>a.num;
    }
}p[N];
multisetrt;
int zero;
mapvis;
int judge(int x)
{
    int pos=1,cnt=zero;
    while(p[pos].num>=x&&p[pos].num>0)
        cnt+=p[pos++].num-x+1;
    return cnt<=x;
}
int check(int x)
{
    vis.clear();
    int pos=1,cnt=zero,money=0;
    while(p[pos].num>=x&&p[pos].num>0)
    {
        int res=p[pos].num-x+1;
        for(multiset::iterator it=st[p[pos].id].begin();res>0;res--,it++)
        {
            money+=*it;
            cnt++;
            vis[{*it,p[pos].id}]++;
        }
        pos++;
    }
    for(multiset::iterator it=rt.begin();cnt0)
        {
            vis[*it]--;
            continue;
        }
        money+=(*it).first;
        cnt++;
    }
    return money;
}
int main()
{
    int n,x,y;
    scanf("%d",&n);
    for(int i=1;ilow+2)
    {
        lm=(low*2+high)/3,rm=(low+high*2)/3;
        if(!judge(lm))
        {
            low=lm;
            continue;
        }
        if(!judge(rm))
        {
            high=rm;
            continue;
        }
        if(check(lm)

你可能感兴趣的:(二分三分)