CF457C Elections

一、题目

点此看题

二、解法

感觉这道题贪心不太好做,考虑暴力一点的方法。

考虑从大到小枚举其他竞选人的最高票数,把超过的人的最便宜的选票买下来,这个是可以继承上一次的操作结果的,然后再看比枚举的最高票数差多少票,再买最便宜的票即可,这个可以用权值线段树维护。

时间复杂度 O ( n log n ) O(n\log n) ,只讲了大体思路,具体写法看代码吧。

#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
#define up 10000
#define inf 0x3f3f3f3f
using namespace std;
const int M = 100005;
int read()
{
 int x=0,flag=1;char c;
 while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
 while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
 return x*flag;
}
int n,m,k,sum,ans=inf,tr[M],s[M];
vector<int> g[M],h[M];
void ins(int i,int l,int r,int id,int f)
{//tr为个数,s为买下所有的钱数
    tr[i]+=f;
    if(l==r)
    {
        s[i]+=f*l;
        return ;
    }
    int mid=(l+r)>>1;
    if(mid>=id) ins(i<<1,l,mid,id,f);
    else ins(i<<1|1,mid+1,r,id,f);
    s[i]=s[i<<1]+s[i<<1|1];
}
int ask(int i,int l,int r,int k)
{
    if(k==0) return 0;
    if(l==r) return l*k;//注意要多少个才给多少个
    int mid=(l+r)>>1;
    if(tr[i<<1]>=k) return ask(i<<1,l,mid,k);
    return s[i<<1]+ask(i<<1|1,mid+1,r,k-tr[i<<1]);
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
    {
        int a=read(),b=read();
        g[a].push_back(b);
        m=max(m,a);
        if(!a) k++;
        else ins(1,0,up,b,1);
    }
    for(int i=1;i<=m;i++)
    {
        sort(g[i].begin(),g[i].end());
        reverse(g[i].begin(),g[i].end());
        for(int j=0;j<g[i].size();j++)
            h[j].push_back(g[i][j]);
    }
    for(int i=n;i>=0;i--)
    {
        for(int j=0;j<h[i].size();j++)
        {
            k++;
            sum+=h[i][j];
            ins(1,0,up,h[i][j],-1);
        }
        ans=min(ans,sum+ask(1,0,up,max(0,i-k+1)));
    }
    printf("%d\n",ans);
}
发布了257 篇原创文章 · 获赞 13 · 访问量 6735

猜你喜欢

转载自blog.csdn.net/C202044zxy/article/details/104149008
今日推荐