USACO铜组测试1

USACO铜组测试1

T1-ABC问题

试题链接

D597u. ABC问题.
时间限制:1.0s 内存限制:256.0MB
输入文件名:abc.in 输出文件名:abc.out
试题来源:USACO
问题描述
Farmer John 的奶牛正在 “mooZ” 视频会议平台上举行每日集会。她们发明了一个简单的数字游戏,为会议增添一些乐趣。
Elsie 有三个正整数 A、B 和 C(A <= B <= C)。这些数字是保密的,她不会直接透露给她的姐妹 Bessie。她告诉 Bessie 七个范围在 1 … 10^9 之间的整数(不一定各不相同),并宣称这是 A、B、C、A+B、B+C、C+A 和 A+B+C 的某种排列。
给定这七个整数,请帮助 Bessie 求出 A、B 和 C。可以证明,答案是唯一的。
输入格式
输入一行,包含七个空格分隔的整数。
输出格式
输出 A、B 和 C,用空格分隔。
输入样例
2 2 11 4 9 7 9
None
输出样例
2 2 7
None
测试点性质
测试点 2-3 满足 C <= 50。
测试点 4-10 没有额外限制。

这题乍一看有些难度,实际上还算简单。
因为a,b,c均为正整数,所以(a+b+c)减去这剩余6个中任意的数都为正整数,所以在这7个数据中(a+b+c)最大,而a最小,b其次。所以排一下序,最小的是a,其次是b,最大的一个是(a+b+c),而c=(a+b+c)-a-b。

#include <bits/stdc++.h>
using namespace std;

int q[10],a,b,c,abc;

int main(){
	freopen("abc.in","r",stdin);
	freopen("abc.out","w",stdout);
	for(int i=1;i<=7;++i){
		scanf("%d",&q[i]);
	}
	sort(q+1,q+8);
	abc=q[7];
	a=q[1],b=q[2],c=abc-a-b;
	printf("%d %d %d\n",a,b,c);
	fclose(stdin);
	fclose(stdout); 
	return 0;
}

T2-雏菊花环

试题链接

Dba3v. 雏菊花环
时间限制:1.0s 内存限制:256.0MB
输入文件名:daisy.in 输出文件名:daisy.out
试题来源:USACO
问题描述
每天,作为她绕农场行走的一部分,奶牛 Bessie 会经过她最喜爱的草地,其中种有 N 朵花(五颜六色的雏菊),编号为 1…N(1≤N≤100),排列成一行。花 i 有 pi 朵花瓣(1≤pi≤1000)。
作为一名崭露头角的摄影家,Bessie 决定给这些花拍些照片。具体地说,对于每一对满足 1≤i≤j≤N 的花 (i,j),Bessie 会给从花 i 到花 j 之间的所有花(包括 i 和 j)拍一张照。
后来 Bessie 查看这些照片时注意到有些照片里存在「平均」的花——一朵恰好有 P 朵花瓣的花,其中 P 等于照片中所有花的花瓣数量的平均值。
Bessie 的照片中有几张存在平均的花?
输入格式
输入的第一行包含 N。第二行包含 N 个空格分隔的整数 p1…pN。
输出格式
输出存在平均的花的照片数量。
输入样例
4
1 1 2 3
None
输出样例
6
None
样例说明
每张仅包含一朵花的照片均会被计入答案(在这个样例中有 4 张)。另外,在这个样例中 (i,j) 为 (1,2) 和 (2,4) 所对应的照片也存在平均的花。

这一题数据量比较小,所以基本上没有超时一类问题。直接写。

#include <bits/stdc++.h>
using namespace std;

int p[110],a[110],n,ans;

int main(){
	freopen("daisy.in","r",stdin);
	freopen("daisy.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		scanf("%d",&p[i]);
	}
	for(int i=1;i<=n;++i){
		a[i]=a[i-1]+p[i];//前缀和
	}
	for(int i=1;i<=n;++i){
		for(int j=i;j<=n;++j){
			int tmp=a[j]-a[i-1];
			if(tmp%(j-i+1)!=0)continue;//平均数是小数则不可能存在平均的花
			else tmp/=j-i+1;
			bool bl=0;
			for(int k=i;k<=j;++k)
				if(p[k]==tmp){
					bl=1;
					break;
				}//找到平均的花
			if(bl)++ans;
		}
	}
	printf("%d\n",ans);
	fclose(stdin);
	fclose(stdout); 
	return 0;
}

但是感兴趣还是可以分析一下O(n2)算法的。O(n2)算法利用一个vh数组存各种数的数量,从而省略查找这一层循环。

#include <bits/stdc++.h>
using namespace std;

int p[110],a[110],vh[1010],n,ans;

int main(){
	freopen("daisy.in","r",stdin);
	freopen("daisy.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		scanf("%d",&p[i]);
	}
	for(int i=1;i<=n;++i){
		a[i]=a[i-1]+p[i];
	}
	for(int i=1;i<=n;++i){
		memset(vh,0,sizeof(vh));//注意清零
		for(int j=i;j<=n;++j){
			vh[p[j]]++;//把新拍到的花的花瓣数标记进vh
			int tmp=a[j]-a[i-1];
			if(tmp%(j-i+1)!=0)continue;
			else tmp/=j-i+1;
			if(vh[tmp])++ans;
		}
	}
	printf("%d\n",ans);
	fclose(stdin);
	fclose(stdout); 
	return 0;
}

T3-一成不变

试题链接

Dlmd0. 一成不变
时间限制:1.0s 内存限制:256.0MB
输入文件名:stuct.in 输出文件名:stuct.out
试题来源:USACO
问题描述
Farmer John 最近扩大了他的农场,从奶牛们的角度看来这个农场相当于是无限大了!奶牛们将农场上放牧的区域想作是一个由正方形方格组成的无限大二维方阵,每个方格中均有美味的草(将每个方格看作是棋盘上的一个方格)。Farmer John 的 N 头奶牛(1≤N≤50)初始时位于不同的方格中,一部分朝向北面,一部分朝向东面。
每一小时,每头奶牛会执行以下二者之一:
如果她当前所在的方格里的草已经被其他奶牛吃掉了,则她会停下。
吃完她当前所在的方格中的所有草,并向她朝向的方向移动一个方格。
经过一段时间,每头奶牛的身后会留下一条被啃秃了的轨迹。
如果两头奶牛在一次移动中移动到了同一个有草的方格,她们会分享这个方格中的草,并在下一个小时继续沿她们朝向的方向移动。
请求出每头奶牛吃到的草的数量。有些奶牛永远不会停下,从而吃到无限多的草。
输入格式
输入的第一行包含 N。以下 N 行,每行描述一头奶牛的起始位置,包含一个字符 N(表示朝向北面) 或 E(表示朝向东面),以及两个非负整数 x 和 y(,)表示方格的坐标。所有 x 坐标各不相同,所有 y 坐标各不相同。
为了使方向和坐标尽可能明确,如果一头奶牛位于方格 (x,y) 并向北移动,她会到达方格 (x,y+1)。如果她向东移动,她会到达方格 (x+1,y)。
输出格式
输出 N 行。输出的第 i 行包含输入中的第 i 头奶牛吃到草的方格的数量。如果一头奶牛可以吃到无限多的草,为这头奶牛输出 “Infinity”。
输入样例
6
E 3 5
N 5 3
E 4 6
E 10 4
N 11 2
N 8 1
None
输出样例
5
3
Infinity
Infinity
2
5
None
测试点性质
测试点 2-5 中,所有坐标不超过 100。
测试点 6-10 没有额外限制。

一开始,我的想法就是挨个判断是否会被截断(附一下代码),但只有10分 算法复杂度O(n2):(下面的if语句都是我模拟得到的,请仔细揣摩)

#include <bits/stdc++.h>
using namespace std;

char to[60];
int x[60],y[60],n,ans;

int main(){
	freopen("stuct.in","r",stdin);
	freopen("stuct.out","w",stdout);
	cin>>n;
	for(int i=1;i<=n;++i){
		cin>>to[i]>>x[i]>>y[i];
	}
	for(int i=1;i<=n;++i){
		int bl=0;
		for(int j=1;j<=n;++j){
			if(i==j)continue;
			if(to[i]=='E'&&to[j]=='N'&&y[i]>=y[j]&&x[i]<=x[j]&&x[j]-x[i]<=y[i]-y[j])
				continue;	
			if(to[i]=='N'&&to[j]=='E'&&y[i]<=y[j]&&x[i]>=x[j]&&y[j]-y[i]<=x[i]-x[j])
				continue;
			if(to[i]=='E'&&to[j]=='E'&&y[j]==y[i]&&x[j]>x[i])
				if(bl==0||bl>x[j]-x[i])
					bl=x[j]-x[i];
			if(to[i]=='N'&&to[j]=='N'&&x[j]==x[i]&&y[j]>y[i])
				if(bl==0||bl>y[j]-y[i])
					bl=y[j]-y[i];
			if(to[i]=='E'&&to[j]=='N'&&y[i]>=y[j]&&x[i]<=x[j])
				if(bl==0||bl>x[j]-x[i])
					bl=x[j]-x[i];
			if(to[i]=='N'&&to[j]=='E'&&y[i]<=y[j]&&x[i]>=x[j])
				if(bl==0||bl>y[j]-y[i])
					bl=y[j]-y[i];
		}
		if(!bl)printf("Infinity\n");
		else printf("%d\n",bl);
	}
	fclose(stdin);
	fclose(stdout); 
	return 0;
}

这个连样例都过不了。原因是:你判断是否会截断第i头牛,方法是看是否会有奶牛与其相交,但是,万一第j头奶牛在截第i头牛前已经被其他就截了呢?!
于是只好模拟,枚举每个小时(可得60分):

#include <bits/stdc++.h>
using namespace std;

int n,vh[60]/*奶牛的行止情况*/,vhash[10010][10010]/*草地的情况(注意这里为了判断是否与其他牛同时来到,如果草被吃则标记上时间)*/,tim; //这里开100是50分,1000是60分,10000也是60分

struct nod{
	char c;
	int x,y,num;
}a[60];

void readp(){
	cin>>n;
	for(int i=1;i<=n;++i)
		cin>>a[i].c>>a[i].x>>a[i].y;
	for(int i=1;i<=n;++i)
		a[i].num=1;
}

bool check(){
	for(int i=1;i<=n;++i)
		if(!vh[i])return true;
	return false;
}

void work(){
	do{
		++tim;
		for(int i=1;i<=n;++i){
			if(vh[i])continue;
			if(a[i].c=='E'){
				if(a[i].x+1>10000){
					a[i].num=-1;
					vh[i]=1;
					continue;
				}//如果出界(一头出界的牛需要一头初始坐标就出界的牛才能截住)则无限
				if(!vhash[a[i].x+1][a[i].y]){
					++a[i].num;
					vhash[a[i].x+1][a[i].y]=tim;
					++a[i].x;
				}//如果此地仍有草
				else if(tim==vhash[a[i].x+1][a[i].y]){
					++a[i].num;
					++a[i].x;
				}//如果与其他牛同时到达
				else vh[i]=1;//否则停止行走
			}
			else{
				if(a[i].y+1>10000){
					a[i].num=-1;
					vh[i]=1;
					continue;
				}
				if(!vhash[a[i].x][a[i].y+1]){
					++a[i].num;
					vhash[a[i].x][a[i].y+1]=tim;
					++a[i].y;
				}
				else if(tim==vhash[a[i].x][a[i].y+1]){
					++a[i].num;
					++a[i].y;
				}
				else vh[i]=1;
			}
		}
	}while(check());
}

void print(){
	for(int i=1;i<=n;++i)
		if(a[i].num==-1)printf("Infinity\n");
		else printf("%d\n",a[i].num);
}

int main(){
	freopen("stuct.in","r",stdin);
	freopen("stuct.out","w",stdout);
	readp();
	work();
	print();
	fclose(stdin);
	fclose(stdout);
	return 0;
}

将坐标进行排序可以解决上面提到的问题(坐标小的比坐标大的要先截到)O(n2)算法100分:

#include <bits/stdc++.h>
using namespace std;

struct nod{
	int x,y,num,id;//num存能走几小时(即多少草),id存位置(方便排完序后按原来顺序输出),x,y是坐标
	nod(int _x=0,int _y=0,int _num=0):x(_x),y(_y),num(_num){}
}E[60],N[60];

int nn,e,ans[60],n;
char to;

bool cmpn(nod q,nod p){
	return q.x<p.x;
}

bool cmpe(nod q,nod p){
	return q.y<p.y;
}

int main(){
	freopen("stuct.in","r",stdin);
	freopen("stuct.out","w",stdout);
	cin>>nn;
	for(int i=1;i<=nn;++i){
		cin>>to;
		if(to=='E'){
			++e;//注意这里不能把++e放在cin里,因为e虽然+1但是后面的>>E[e].y仍然使用的是原来的e
			cin>>E[e].x>>E[e].y;
			E[e].id=i;
		}
		else{
			++n;
			cin>>N[n].x>>N[n].y;
			N[n].id=i;
		}
	}
	sort(E+1,E+e+1,cmpe);
	sort(N+1,N+n+1,cmpn);
	for(int i=1;i<=e;++i){
		for(int j=1;j<=n;++j){
			if(E[i].y<N[j].y||E[i].x>N[j].x)continue;//不相交
			if(N[j].x-E[i].x==E[i].y-N[j].y)continue;//同时到达,对双方都没有影响
			int a=N[j].x,b=E[i].y;
			if(b-N[j].y>a-E[i].x&&(N[j].num==0||b-N[j].y<N[j].num)&&(E[i].num==0||E[i].num>a-E[i].x)){
				ans[N[j].id]=N[j].num=b-N[j].y;//注意N[j].num只是为了比较方便,实际上可以被ans代替
			}
			else if(b-N[j].y!=a-E[i].x&&(E[i].num==0||a-E[i].x<E[i].num)&&(N[j].num==0||N[j].num>b-N[j].y)){//其实就等于if(b-N[j].y<a-E[i].x&&(E[i].num==0||a-E[i].x<E[i].num)&&(N[j].num==0||N[j].num>b-N[j].y))
				ans[E[i].id]=E[i].num=a-E[i].x;
			}
		}
	}
	for(int i=1;i<=nn;++i)
		if(ans[i])printf("%d\n",ans[i]);
		else printf("Infinity\n");
	fclose(stdin);
	fclose(stdout); 
	return 0;
}
posted @ 2023-01-14 19:21  whznfy  阅读(19)  评论(0)    收藏  举报  来源