Google Code Jam 2015 Round 1A 解題報告
阿新 • • 發佈:2019-01-26
太弱了,比賽時只出了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; }