太弱了,比赛时只出了A的大数据和BC小数据,排到1700+。赛后才把B的小数据过了。
A. Mushroom Monster
就是贪心模拟。第一种吃法,只有当前时刻比10秒前少才去吃减少的量,否则不吃。第二种吃法,计算每十秒的减少量,以减少量最大的作为平均速率去吃。
#include <bits/stdc++.h> using namespace std; int m[10010]; int main(){ freopen("A-large.in","r",stdin); freopen("A-large.out","w",stdout); int t; cin>>t; int x=0; while(t--){ x++; int n; cin>>n; for(int i=1;i<=n;i++){ scanf("%d",&m[i]); } int y=0; int MAX_speed=0; for(int i=2;i<=n;i++){ if(m[i]<m[i-1]){ y+=m[i-1]-m[i]; if(m[i-1]-m[i]>MAX_speed){ MAX_speed=m[i-1]-m[i]; } } } int z=0; for(int i=1;i<n;i++){ if(m[i]<MAX_speed){ z+=m[i]; }else{ z+=MAX_speed; } } printf("Case #%d: %d %d\n",x,y,z); } return 0; }
B. Haircut
建立一个优先队列去模拟,队列大小是理发师人数,每次有人理完发(pop),下一个人接着上(push)。解题关键在减小模拟的量,因为模拟n个人会超时。小数据可以求时间的公倍数,计算出公倍数时间能理的人数,用总人数模它。大数据则需要二分找一个接近理完但是没有理完的时间,从那个时间开始模拟。
#include <bits/stdc++.h> using namespace std; #define ll long long int m[1010]; struct node{ int idx; ll tot_time; node(int idx,ll tot_time):idx(idx),tot_time(tot_time){ } node(){ } bool operator <(const node& other)const{ if(tot_time!=other.tot_time){ return tot_time>other.tot_time; } return idx>other.idx; } }; int main(){ freopen("B-large-practice.in","r",stdin); freopen("B-large-practice.out","w",stdout); int t; cin>>t; int cas=0; while(t--){ cas++; int b,n; cin>>b>>n; priority_queue<node> que; ll MAX_time=0; ll MIN_time=100000; for(int i=1;i<=b;i++){ scanf("%d",&m[i]); if(m[i]>MAX_time)MAX_time=m[i]; if(m[i]<MIN_time)MIN_time=m[i]; } ll l=(n*MIN_time)/b-MAX_time; ll r=(n*MAX_time)/b+MAX_time; ll aTime=l; while(l<=r){ ll mid=(l+r)>>1; ll cnt=0; for(int i=1;i<=b;i++){ cnt+=mid/m[i]; if(mid%m[i])cnt++; if(cnt>=n)break; } if(cnt>=n){ r=mid-1; }else{ l=mid+1; aTime=mid; } } ll cnt=0; for(int i=1;i<=b;i++){ cnt+=aTime/m[i]; if(aTime%m[i])cnt++; que.push( node(i, (m[i]-aTime%m[i])%m[i] ) ); } for(int i=cnt+1;i<n;i++){ node cur=que.top(); que.pop(); que.push( node( cur.idx,cur.tot_time+m[cur.idx]) ); } node ans=que.top(); printf("Case #%d: %d\n",cas,ans.idx); } return 0; }
C. Logging
一看到凸包有点蒙了,不过解法貌似不需要凸包。小数据可以枚举每个点i,然后再枚举每个不同于i的点j,连接ij,用叉积计算直线两侧有多少点,取较小的那一侧,对所有j取最小值。这个结果就是为了使i在凸包上需要去掉的点数。大数据不会做。。。
#include <bits/stdc++.h> using namespace std; #define ll long long struct Point{ ll x,y; Point(ll x,ll y):x(x),y(y){ } Point(){ } }pts[3010]; struct Vector{ ll x,y; Vector(ll x,ll y):x(x),y(y){ } Vector(){ } Vector(Point A,Point B){ x=B.x-A.x; y=B.y-A.y; } }; ll Cross(Vector A,Vector B){ return A.x*B.y - A.y*B.x; } int main(){ freopen("C-small-attempt2.in","r",stdin); freopen("C-small-attempt2.out","w",stdout); int t; cin>>t; int cas=0; while(t--){ cas++; int n; cin>>n; for(int i=1;i<=n;i++){ cin>>pts[i].x>>pts[i].y; } printf("Case #%d:\n",cas); for(int i=1;i<=n;i++){ int ans=max(n-3,0); for(int j=1;j<=n;j++){ //枚举 if(i==j)continue; int left=0; int right=0; for(int k=1;k<=n;k++){ if(k==i)continue; if(k==j)continue; Vector v1 = Vector(pts[i],pts[j]); Vector v2 = Vector(pts[i],pts[k]); ll cp = Cross(v1,v2); if(cp<0)left++; if(cp>0)right++; } int tmp=min(left,right); ans=min(ans,tmp); } cout<<ans<<endl; } } return 0; }