题目来自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 }
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\n",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\n"); 11 return 0; 12 } 13 if(a==b) 14 { 15 printf("Even %d\n",a+b); 16 } 17 else 18 { 19 int maxn=max(a,b); 20 printf("Odd %d\n",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\n",ans); 78 return 0; 79 }