[51nod] 1494 选举拉票 #算法设计策略
2017-10-31 14:03
267 查看
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的钱。Output
你是0号候选人(所以,如果一个选民选你的话ai就是0,这个时候bi也肯定是0)。
输出一个整数表示花费的最少的钱。Input示例
5 1 2 1 2 1 2 2 1 0 0Output示例
3Analysis分析 正解:算法设计策略 + 线段树 为什么特别标上这个算法设计策略呢 这道题思路实在太复杂qwq
我们可以想象有多个河内塔,一个塔就是一个候选人,塔中一片就是一个选民,候选人的“决心”越大片越大 因此我们这样排序:每个候选人的选票小票在上大票在下(笑) 那么我们怎么抢票呢? 宏观策略是这样的:抢票数最高的候选人最便宜的票 因此就是从每个塔的顶端拿选票堆在自己的塔上,直到自己的塔最高 所以这个东西想了我一个下午+一个晚上 所以我最后去看题解了(听说CCZ和SXT是第四个和第五个AC的orz) 题解的意思是这样:从大到小枚举最终得票数, 然后根据每次的不同选择计算出来的结果更新答案 那么我枚举到自己有 i 张票的时候,需要保证其他候选人的票 < i 所以他们多出来的票我就都收了(当然收的是最便宜的,这里用优先队列维护) 砍完候选人的票之后,我的票可能仍然不够 i 张,定义我之前抢过来的票数为 num , 那么从票仓里再提取出 i - num + 投自己的最初的选票 张票即可 当然这里是提取前 k 张最小的 这里可以用权值线段树维护 这样,我们从大到小枚举,因此枚举到第 i-1 张时,可以直接继承第 i 张的投票情况,无需初始化 详情请看代码 注意,票价是可以为 0 且不为自己选民的 Code代码
#include<stdio.h> #include<queue> #include<algorithm> #include<iostream> #define mid (L+R)/2 #define lc (rt<<1) #define rc (rt<<1|1) #define maxn 200000 using namespace std; long long n,list[maxn],qwq; bool vis[maxn]; struct nodd{ long long num,sum; }T[maxn*4]; void modify(long long rt,long long L,long long R,long long pos,long long val){ if(pos < L || pos > R) return; if(L == R) T[rt].num += val,T[rt].sum += val*pos; else{ /*if(pos <= mid)*/ modify(lc,L,mid,pos,val); /*else*/ modify(rc,mid+1,R,pos,val); T[rt].num = T[lc].num+T[rc].num; T[rt].sum = T[lc].sum+T[rc].sum; } } long long query(long long rt,long long L,long long R,long long pos){ if(pos <= 0) return 0; if(pos > T[rt].num) return 2e9; if(L == R) return L*pos;//T[rt].sum; else if(pos <= T[lc].num) return query(lc,L,mid,pos); else return T[lc].sum + query(rc,mid+1,R,pos-T[lc].num); } priority_queue<long long,vector<long long> ,greater<long long> > heap[maxn]; bool cmp1(long long A,long long B){ return heap[A].size() > heap[B].size(); } int main(){ scanf("%lld",&n); for(int i = 1;i <= n;i++){ long long x,y; scanf("%lld%lld",&x,&y); heap[x].push(y); if(x&&!vis[x]) list[++qwq] = x,vis[x] = true; if(x) modify(1,0,20000,y,1); } sort(list+1,list+1+qwq,cmp1); // cout << "list"; // for(int i = 1;i <= qwq;i++) printf("%d ",list[i]); cout << endl; long long s = heap[0].size(),num = 0,sum = 0,ans = 2e9; for(int i = n;i >= max(1LL,s);i--){ for(int j = 1;j <= qwq;j++){ if(heap[list[j]].size() < i) break; while(heap[list[j]].size() >= i){ sum += heap[list[j]].top(); modify(1,0,20000,heap[list[j]].top(),-1); heap[list[j]].pop(); num++; } }ans = min(ans,sum+query(1,0,20000,i-(num+s))); // printf("#%d: ans %d\n",i,ans); } printf("%lld",ans); return 0; }高效算法设计策略
相关文章推荐
- 51nod 1494 选举拉票 | 线段树
- 51nod 1494 选举拉票【贪心】【扫描线】【线段树】
- 51nod 1494 选举拉票&&cf458C
- 51Nod-1494-选举拉票
- 【51nod】1494 选举拉票 扫描线+线段树
- 51nod 1206 1028 1494题解+扫描线模板
- [枚举 线段树] 51Nod1494 选举拉票
- 【51Nod1494】选举拉票
- 选举拉票正在进行时
- ZooKeeper Leader选举
- 【51nod 1028】 大数乘法 V2 【FFT/NTT】
- 51nod 1105 第K大的数 (二分答案)
- 51Nod-1513-树上的回文
- 51nod 1066 Bash游戏
- 51nod 1202 子序列的个数 dp
- 51nod 1453:抽彩球
- zookeeper原理(选举,应用)
- elasticsearch选举master
- 51Nod 1786 数据流中的算法-众数 题解
- 51NOD 1020 逆序排列