Google Code Jam 2015 Round 1A 解题报告

        太弱了,比赛时只出了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;
}


你可能感兴趣的:(GoogleCodeJam)