[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\n",i,ans); 68 } 69 70 printf("%lld",ans); 71 72 return 0; 73 }
转载请注明出处 -- 如有意见欢迎评论