寒假第三次训练-花式STL
A - Moo University - Financial Aid
题目大意:给定c组数据,形式为:分数+资金,要求选出n(n为奇数)组,保证不仅资金总和小于f,而且分数中位数最大。
解题思路:先排序数据,分数由高到低选定一组数据,数据前方后方都有(n-1)/2组数据,建立low[i]表示中位数为第i组数据的分数时,前方最小资金和,up[i]同理。low[i]和up[i]用priority_queue计算,保证队列内部有不超过(n-1)/2的元素,一旦溢出就pop最大的元素。
AC代码:
#include <cstdio>#include <algorithm>#include <string>#include <iostream>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <queue>#define MAXC 100010using namespace std;pair<int,int> cow[MAXC];long long low[MAXC],up[MAXC];int main(){ int N,C,i,m,f=0; long long F,sum=0; scanf("%d%d%I64d",&N,&C,&F); for (i=0; i<C; i++) scanf("%d%d",&cow[i].first,&cow[i].second); sort(cow,cow+C); m=(N-1)/2; priority_queue<int> q1,q2; for (i=0; i<C; i++) { int flag=0; if (q1.size()==m) { flag=1; low[i]=sum; q1.push(cow[i].second); sum+=cow[i].second; sum-=q1.top(); q1.pop(); } if (flag==0) { q1.push(cow[i].second); sum+=cow[i].second; } } sum=0; for (i=C-1; i>=0; i--) { int flag=0; if (q2.size()==m) { flag=1; up[i]=sum; q2.push(cow[i].second); sum+=cow[i].second; sum-=q2.top(); q2.pop(); } if (flag==0) { q2.push(cow[i].second); sum+=cow[i].second; } } for (i=C-m-1; i>=m; i--) { //printf("low:%d up:%d\n",low[i],up[i]); if (low[i]+cow[i].second+up[i]<=F) { f=1; printf("%d\n",cow[i].first); break; } } if(f==0) printf("-1\n"); return 0;}
B - Sockets
题目大意:有n台电脑,m个插座,电脑和插座都有自己的power,必须满足power相等才能将电脑连接插座,现在提供无限个适配器,可以将插座的power变为(power+1)/2,一个插座上可以加无限个适配器,求最大的电脑连接量同时满足适配器使用最少,输出每一台电脑对应的插座和每一个插座插入的适配器。
解题思路:将插座的power排序,电脑放入map,以power为关键字排序,一边给插座加适配器,一边在map里查找power刚好相等的电脑,因为同一台电脑要使适配器最少的话肯定是从power本来就小的插座开始加适配器,值得注意的是电脑的power可能重复,map是不允许重复的,我们利用vector来解决。
AC代码:
#include <iostream>#include <cstdio>#include <string>#include <algorithm>#include <map>#include <vector>using namespace std;struct Soc{ long long x; int pos;};#define MAX 200005map<long long,int> pc;struct Soc soc[MAX];int pc_soc[MAX]={0};long long adp[MAX]={0};vector<int> pc_mul[MAX];bool compare(Soc a,Soc b){ return a.x<b.x;}int main(){ int n,m,i,c=0,count_=0; long long a,b,u=0,u1=0,temp; scanf("%d%d",&n,&m); for (i=1;i<=n;i++) { int x; scanf("%I64d",&a); x=pc[a]; if (x==0) { pc[a]=++count_; pc_mul[count_].push_back(i); } else { pc_mul[x].push_back(i); } } for (i=1;i<=m;i++) { scanf("%I64d",&soc[i].x); soc[i].pos=i; } sort(soc+1,soc+m+1,compare); for (i=1;i<=m;i++) { int flag=0; u1=0; temp=soc[i].x; map<long long,int>::iterator iter; while (temp) { if((iter=pc.find(temp)) != pc.end()) { if (pc_mul[iter->second].size()>0) { flag=1; int p=pc_mul[iter->second].size(); c++; pc_soc[pc_mul[iter->second][p-1]]=soc[i].pos; pc_mul[iter->second].pop_back(); break; } } if (temp==1) break; else { temp=(temp+1)/2; u1++; } } if (flag==0) u1=0; u+=u1; adp[soc[i].pos]+=u1; } printf("%d %I64d\n",c,u); for(i=1;i<=m;i++) printf("%I64d%c",adp[i],i==m?'\n':' '); for(i=1;i<=n;i++) printf("%d%c",pc_soc[i],i==n?'\n':' ');}
C - HDU Today
题目大意:给定n组形式为:地点a,地点b,时间(a,b为字符串),并且知道起止地点,求最短时间
解题思路:将字符串转换为数字下标,用最短路算
AC代码:
#include <iostream>#include <cstdio>#include <string>#include <algorithm>#include <map>#include <vector>using namespace std;struct Soc{ long long x; int pos;};#define MAX 200005map<long long,int> pc;struct Soc soc[MAX];int pc_soc[MAX]={0};long long adp[MAX]={0};vector<int> pc_mul[MAX];bool compare(Soc a,Soc b){ return a.x<b.x;}int main(){ int n,m,i,c=0,count_=0; long long a,b,u=0,u1=0,temp; scanf("%d%d",&n,&m); for (i=1;i<=n;i++) { int x; scanf("%I64d",&a); x=pc[a]; if (x==0) { pc[a]=++count_; pc_mul[count_].push_back(i); } else { pc_mul[x].push_back(i); } } for (i=1;i<=m;i++) { scanf("%I64d",&soc[i].x); soc[i].pos=i; } sort(soc+1,soc+m+1,compare); for (i=1;i<=m;i++) { int flag=0; u1=0; temp=soc[i].x; map<long long,int>::iterator iter; while (temp) { if((iter=pc.find(temp)) != pc.end()) { if (pc_mul[iter->second].size()>0) { flag=1; int p=pc_mul[iter->second].size(); c++; pc_soc[pc_mul[iter->second][p-1]]=soc[i].pos; pc_mul[iter->second].pop_back(); break; } } if (temp==1) break; else { temp=(temp+1)/2; u1++; } } if (flag==0) u1=0; u+=u1; adp[soc[i].pos]+=u1; } printf("%d %I64d\n",c,u); for(i=1;i<=m;i++) printf("%I64d%c",adp[i],i==m?'\n':' '); for(i=1;i<=n;i++) printf("%d%c",pc_soc[i],i==n?'\n':' ');}
F - Pearls in a Row
题目大意:给定n个数字,要求用隔板法在数字间进行划分,划分出的每一组必须包含至少两个一样的数字,求插入隔板最多的方案的每一组首尾的下标,若不存在输出-1
解题思路:从前往后读一个数据向map存一个数据,并判断是否已经存在相同数字,有则记录并且销毁map,这样贪心的读到两个相同数就记录。值得注意的是相同数的第一个数记录的应该是一段数据最左端的下标,第二个数记录的是本身的下标,但是如果作为最后一段数据,相同数的第二个数却不是输入数据的最后一个就需要把记录的值改为最后数的下标。
AC代码:
#include <iostream>#include <cstdio>#include <string>#include <algorithm>#include <map>#include <vector>#include <cstring>using namespace std;#define MAXN 300005typedef struct Seg{ long long left; long long right;} seg;long long pearl[MAXN];vector<seg> rec;map<long long,int> p;int main(){ long long n,count_=0,k=1; scanf("%I64d",&n); for (long long i=1; i<=n; i++) { scanf("%I64d",&pearl[i]); long long x; x=p[pearl[i]]; if (x==0) p[pearl[i]]=k; else { seg temp; temp.left=p[pearl[i]]; temp.right=i; k=i+1; rec.push_back(temp); p.clear(); count_++; } } if (count_!=0 && rec.back().right!=n) rec.back().right=n; if (count_==0) printf("-1\n"); else { printf("%I64d\n",count_); for (long long i=0; i<rec.size(); i++) printf("%I64d %I64d\n",rec[i].left,rec[i].right); }}