题目来自NCPC2017
B题:Best Relay Team
直接按照题意做
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 struct node 6 { 7 string name; 8 double n1; 9 double n2; 10 }a[505]; 11 12 bool cmp(node a,node b) 13 { 14 return a.n2<b.n2; 15 } 16 17 int main() 18 { 19 int n; 20 cin>>n; 21 for(int i=0;i<n;i++) 22 { 23 cin>>a[i].name>>a[i].n1>>a[i].n2; 24 } 25 sort(a,a+n,cmp); 26 string ansnm = a[0].name; 27 double ans = INT_MAX; 28 for(int i=0;i<n;i++) 29 { 30 int cnt = 1; 31 double now = a[i].n1; 32 for(int j=0;j<n;j++) 33 { 34 if(j!=i) 35 { 36 now += a[j].n2; 37 cnt++; 38 } 39 if(cnt==4) 40 { 41 break; 42 } 43 } 44 45 if(now<ans) 46 { 47 ansnm = a[i].name; 48 ans = now; 49 } 50 } 51 cout<<ans<<endl<<ansnm<<endl; 52 return 0; 53 }
E题:Emptying the Baltic
有一张地图,地图上有每个区域的海拔高度,负数表示海平面以下,被水覆盖;正数表示海平面以上,没有水。在(x,y)的海底处安装一个抽水装置。水只能往低处流,或者流向抽水机。问抽水机能抽多少水
用优先队列+bfs。bfs过程中,对于两个相邻的海底区域,每次取高度的最大值,放到优先队列(高度高的在前面)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int d[8][2]={{0,1},{0,-1},{1,0},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1}}; 4 int n,m,vis[505][505],h[505][505],a[505][505]; 5 struct node 6 { 7 int x,y,h; 8 bool operator<(const node &b)const 9 { 10 return h>b.h; 11 } 12 }; 13 int x,y; 14 void bfs() 15 { 16 priority_queue<node>q; 17 node fir,nxt; 18 fir.x=x; 19 fir.y=y; 20 fir.h=a[x][y]; 21 q.push(fir); 22 while(!q.empty()) 23 { 24 fir=q.top();q.pop(); 25 for(int i=0;i<8;i++) 26 { 27 int xx=fir.x+d[i][0]; 28 int yy=fir.y+d[i][1]; 29 if(xx<1||yy<1||xx>n||yy>m||vis[xx][yy]||a[xx][yy]>=0) continue; 30 nxt.x=xx; 31 nxt.y=yy; 32 nxt.h=max(fir.h,a[xx][yy]); 33 h[xx][yy]=nxt.h; 34 vis[xx][yy]=1; 35 q.push(nxt); 36 } 37 } 38 return ; 39 } 40 int main() 41 { 42 scanf("%d%d",&n,&m); 43 for(int i=1;i<=n;i++) 44 { 45 for(int j=1;j<=m;j++) 46 { 47 scanf("%d",&a[i][j]); 48 } 49 } 50 scanf("%d%d",&x,&y); 51 h[x][y]=a[x][y]; 52 vis[x][y]=1; 53 bfs(); 54 long long ans=0; 55 for(int i=1;i<=n;i++) 56 { 57 for(int j=1;j<=m;j++) 58 { 59 ans+=-1LL*h[i][j]; 60 } 61 } 62 printf("%lld ",ans); 63 return 0; 64 }
G题:Galactic Collegiate Programming Contest
模拟滚榜,在每个事件下面只看第一个队伍的排名,排名的规则是:The score of team t 1 is better than that of t 2 if either a1 > a2 , or if a1 = a2 and b1 < b2 . The rank of a team is k + 1 where k is the number of teams whose score is better. 注意:如果有一支队伍的出题数目和罚时都和第一支队伍相当,那么这支队伍会在第一支队伍下面,排名不会比第一支队伍高
第一种方法是用multiset,把结构体放到multiset中并且重载'<'
第二种方法是用优先队列,并且要用一个变量来表示当前优先队列的元素个数sum,还要有一个数组来判断当前队伍是否已经被放入队列里,最后再把不合法的队伍从队列里取出,并同时相应的改变sum的值和队伍的状态
第三种方法是我们可以把出题数和罚时转换成相应的数值,我们会发现这些数值与一支队伍的出题数和罚时是相对应的。但我们要注意罚时要取差值。然后我们仍然可以用第一种方法,把数值放到multiset中。或者我们可以先离线,然后用树状数组
给出第一种的代码:
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 struct node 5 { 6 int t,p,pos; 7 bool operator<(const node &b)const //注意这个地方的重载,要理解 8 { 9 if(t==b.t) 10 { 11 if(p==b.p) 12 return pos>b.pos; 13 return p>b.p; 14 } 15 return t<b.t; 16 } 17 }a[100005]; 18 multiset<node>s; //multiset可支持重复元素 19 int main() 20 { 21 int n,m; 22 scanf("%d%d",&n,&m); 23 for(int i=0;i<=n;i++) 24 { 25 a[i].t=0; 26 a[i].p=0; 27 a[i].pos=i; 28 } 29 int x,y; 30 31 while(m--) 32 { 33 scanf("%d%d",&x,&y); 34 if(x==1) 35 { 36 a[x].t++; 37 a[x].p+=y; 38 } 39 else 40 { 41 if(a[1]<a[x]) //如果当前队伍原来已经在set里了,我们需要先把他删除 42 { 43 s.erase(s.find(a[x]));//erase里一定要是要删除元素所对应的迭代器,因为我们只需要删除一个 44 //如果传入的是这个元素,那么所有与它相等的元素都会被删除 45 } 46 a[x].t++; 47 a[x].p+=y; 48 s.insert(a[x]); 49 } 50 multiset<node>::iterator it; 51 for(it=s.begin();it!=s.end();)//要注意这里的写法,for循环里不用写it++,因为我们规定的是排名比第一支队伍小的放在前面 52 //所以我们应该是从前往后删除不合法的 53 { 54 if((*it)<a[1]) 55 { 56 s.erase(it++); //特别注意这个地方的写法,erase里应该是it++!!! 57 } 58 else 59 break; 60 } 61 printf("%d ",s.size()+1); 62 } 63 return 0; 64 }
I题:Judging Moose
直接写
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 int a,b; 5 int main() 6 { 7 scanf("%d%d",&a,&b); 8 if(a==0&&b==0) 9 { 10 printf("Not a moose "); 11 return 0; 12 } 13 if(a==b) 14 { 15 printf("Even %d ",a+b); 16 } 17 else 18 { 19 int maxn=max(a,b); 20 printf("Odd %d ",2*maxn); 21 } 22 23 return 0; 24 } 25
J题:Kayaking Trip
二分+贪心
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 struct node 5 { 6 int first,second,sum; 7 }op[10]; 8 int per[5],s[5],num[5]; 9 int n; 10 int c[50050]; 11 bool check(int mid) 12 { 13 for(int i=1;i<=3;i++) 14 { 15 num[i]=per[i]; 16 } 17 for(int i=1;i<=n;i++) 18 { 19 int flag=0; 20 for(int j=1;j<=6;j++) 21 { 22 if(num[op[j].first]==0||num[op[j].second]==0||op[j].sum*c[i]<mid) 23 { 24 continue; 25 } 26 if(op[j].first==op[j].second&&num[op[j].first]<2) 27 { 28 continue; 29 } 30 num[op[j].first]--; 31 num[op[j].second]--; 32 flag=1; 33 break; 34 } 35 if(flag==0) 36 { 37 return 0; 38 } 39 } 40 return 1; 41 } 42 int main() 43 { 44 scanf("%d %d %d",&per[1],&per[2],&per[3]); 45 scanf("%d %d %d",&s[1],&s[2],&s[3]); 46 n=per[1]+per[2]+per[3]; 47 n/=2; 48 for(int i=1;i<=n;i++) 49 { 50 scanf("%d",&c[i]); 51 } 52 sort(c+1,c+1+n); 53 int k=1; 54 for(int i=1;i<=3;i++) 55 { 56 for(int j=i;j<=3;j++) 57 { 58 op[k].first=i; 59 op[k].second=j; 60 op[k++].sum=s[i]+s[j]; 61 } 62 } 63 int r=400000000,l=0,mid,ans; 64 while(r-l>=0) 65 { 66 mid=(r+l)/2; 67 if(check(mid)) 68 { 69 ans=mid; 70 l=mid+1; 71 } 72 else 73 { 74 r=mid-1; 75 } 76 } 77 printf("%d ",ans); 78 return 0; 79 }