zoukankan      html  css  js  c++  java
  • [51nod] 1494 选举拉票 #算法设计策略

    1494 选举拉票

    题目来源: CodeForces 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题

    现在你要竞选一个县的县长。你去对每一个选民进行了调查。你已经知道每一个人要选的人是谁,以及要花多少钱才能让这个人选你。现在你想要花最少的钱使得你当上县长。你当选的条件是你的票数比任何一个其它候选人的多(严格的多,不能和他们中最多的相等)。请计算一下最少要花多少钱。

    Input
    单组测试数据。
    第一行有一个整数n (1 ≤ n ≤ 10^5),表示这个县的选民数目。
    接下来有n行,每一行有两个整数ai 和 bi (0 ≤ ai ≤ 10^5; 0 ≤ bi ≤ 10^4),表示第i个选民选的是第ai号候选人,想要让他选择自己就要花bi的钱。
    你是0号候选人(所以,如果一个选民选你的话ai就是0,这个时候bi也肯定是0)。
    Output
    输出一个整数表示花费的最少的钱。
    Input示例
    5
    1 2
    1 2
    1 2
    2 1
    0 0
    Output示例
    3
    Analysis分析
    正解:算法设计策略 + 线段树
    为什么特别标上这个算法设计策略呢
    这道题思路实在太复杂qwq
    我们可以想象有多个河内塔,一个塔就是一个候选人,塔中一片就是一个选民,候选人的“决心”越大片越大
    因此我们这样排序:每个候选人的选票小票在上大票在下(笑)
    那么我们怎么抢票呢?
    宏观策略是这样的:抢票数最高的候选人最便宜的票
    因此就是从每个塔的顶端拿选票堆在自己的塔上,直到自己的塔最高
    所以这个东西想了我一个下午+一个晚上
    所以我最后去看题解了(听说CCZ和SXT是第四个和第五个AC的orz)
    题解的意思是这样:从大到小枚举最终得票数, 然后根据每次的不同选择计算出来的结果更新答案
    那么我枚举到自己有 i 张票的时候,需要保证其他候选人的票 < i
    所以他们多出来的票我就都收了(当然收的是最便宜的,这里用优先队列维护)
    砍完候选人的票之后,我的票可能仍然不够 i 张,定义我之前抢过来的票数为 num ,
    那么从票仓里再提取出 i - num + 投自己的最初的选票 张票即可
    当然这里是提取前 k 张最小的
    这里可以用权值线段树维护
    这样,我们从大到小枚举,因此枚举到第 i-1 张时,可以直接继承第 i 张的投票情况,无需初始化
    详情请看代码
    注意,票价是可以为 0 且不为自己选民的
     
    Code代码
     1 #include<stdio.h>
     2 #include<queue>
     3 #include<algorithm>
     4 #include<iostream>
     5 #define mid (L+R)/2
     6 #define lc (rt<<1)
     7 #define rc (rt<<1|1)
     8 #define maxn 200000
     9 using namespace std;
    10 
    11 long long n,list[maxn],qwq;
    12 bool vis[maxn];
    13 
    14 struct nodd{
    15     long long num,sum;
    16 }T[maxn*4];
    17 
    18 void modify(long long rt,long long L,long long R,long long pos,long long val){
    19     if(pos < L || pos > R) return;
    20     if(L == R) T[rt].num += val,T[rt].sum += val*pos;
    21     else{
    22         /*if(pos <= mid)*/ modify(lc,L,mid,pos,val);
    23         /*else*/ modify(rc,mid+1,R,pos,val);
    24         T[rt].num = T[lc].num+T[rc].num;
    25         T[rt].sum = T[lc].sum+T[rc].sum;
    26     }
    27 }
    28 
    29 long long query(long long rt,long long L,long long R,long long pos){
    30     if(pos <= 0) return 0;
    31     if(pos > T[rt].num) return 2e9;
    32     if(L == R) return L*pos;//T[rt].sum;
    33     else if(pos <= T[lc].num) return query(lc,L,mid,pos);
    34     else return T[lc].sum + query(rc,mid+1,R,pos-T[lc].num);
    35 }
    36 
    37 priority_queue<long long,vector<long long> ,greater<long long> > heap[maxn];
    38 
    39 bool cmp1(long long A,long long B){ return heap[A].size() > heap[B].size(); }
    40 
    41 int main(){
    42     scanf("%lld",&n);
    43     
    44     for(int i = 1;i <= n;i++){
    45         long long x,y;
    46         scanf("%lld%lld",&x,&y);
    47         heap[x].push(y);
    48         if(x&&!vis[x]) list[++qwq] = x,vis[x] = true;
    49         if(x) modify(1,0,20000,y,1);
    50     }
    51     
    52     sort(list+1,list+1+qwq,cmp1);
    53 //    cout << "list";
    54 //    for(int i = 1;i <= qwq;i++) printf("%d ",list[i]); cout << endl;
    55     long long s = heap[0].size(),num = 0,sum = 0,ans = 2e9;
    56     
    57     for(int i = n;i >= max(1LL,s);i--){
    58         for(int j = 1;j <= qwq;j++){
    59             if(heap[list[j]].size() < i) break;
    60             while(heap[list[j]].size() >= i){
    61                 sum += heap[list[j]].top();
    62                 modify(1,0,20000,heap[list[j]].top(),-1);
    63                 heap[list[j]].pop();
    64                 num++;
    65             }
    66         }ans = min(ans,sum+query(1,0,20000,i-(num+s)));
    67 //        printf("#%d: ans %d
    ",i,ans);
    68     }
    69     
    70     printf("%lld",ans);
    71     
    72     return 0;
    73 }
    高效算法设计策略
  • 相关阅读:
    将代码托管到github服务器之SSH验证
    将代码托管到github服务器之HTTPS验证
    git的基本介绍和使用
    iOS之UITableView组头组尾视图/标题悬停
    iOS事件传递->处理->响应
    NSRunLoop
    Podfile使用说明
    cocoapods安装
    block
    自定义UIBarButtonItem
  • 原文地址:https://www.cnblogs.com/Chorolop/p/7761186.html
Copyright © 2011-2022 走看看