USACO 2021 February Contest, Bronze

USACO 2021 February Contest, Bronze

Problem 1. Year of the Cow

Farmer John 的奶牛们得知最近正在庆祝牛年的到来时十分兴奋。牛年总是奶牛们的最爱。

我们知道,中国历法中每一年所对应的生肖遵循 12 年的周期:Ox, Tiger, Rabbit, Dragon, Snake, Horse, Goat, Monkey, Rooster, Dog, Pig, Rat(牛、虎、兔、龙、蛇、马、羊、猴、鸡、狗、猪、鼠),然后回到牛。

奶牛 Bessie 自豪地说她是在许多年前的一个牛年出生的。她的朋友 Elsie 想要知道她与 Bessie 出生相差多少年,并且希望你能够通过查看农场上若干奶牛出生年份之间的关系来帮助她推算。

输入格式(从终端 / 标准输入读入):

输入的第一行包含一个整数 N N N 1 ≤ N ≤ 100 1≤N≤100 1N100)。以下 N N N 行每行包含一个 8 个单词的短语,指定了两头奶牛的出生年份之间的关系,格式为

“Mildred born in previous Dragon year from Bessie”(Mildred 在 Bessie 出生的前一个龙年出生),

“Mildred born in next Dragon year from Bessie”(Mildred 在 Bessie 出生的后一个龙年出生)。

最后一个单词是农场上某一头奶牛的名字,为 “Bessie” 或一头已经在之前的输入中出现过的奶牛。

第一个单词是农场上某一头奶牛的名字,不为 “Bessie” 且未在之前的输入中出现过。所有的奶牛名字不超过 10 个字符,且仅包含字符 a…z 或 A…Z。

第 5 个单词是上述十二生肖之一。

第 4 个单词是 “previous”(之前)或 “next”(之后)之一。例如,如果短语为 “Mildred born in previous Dragon year from Bessie”,则 Mildred 的出生年份为最为接近且严格处于 Bessie 的出生年份之前(不等于)的龙年。

输出格式(输出至终端 / 标准输出):

输出 Bessie 和 Elsie 的出生年份之间相差的年数。输入保证可以通过给定的信息求出结果。

输入样例:
4
Mildred born in previous Dragon year from Bessie
Gretta born in previous Monkey year from Mildred
Elsie born in next Ox year from Gretta
Paulina born in next Dog year from Bessie
输出样例:
12

在以上的输入中,

  • Elsie 在 Bessie 之前 12 年出生。
  • Mildred 在 Bessie 之前 9 年出生。
  • Gretta 在 Bessie 之前 17 年出生。
  • Paulina 在 Bessie 之前 9 年出生。

供题:Brian Dean

分析:

将名字映射成数字,通过给出的关系求解。

建树:

最后一个单词是农场上某一头奶牛的名字,为 “Bessie” 或一头已经在之前的输入中出现过的奶牛。

第一个单词是农场上某一头奶牛的名字,不为 “Bessie” 且未在之前的输入中出现过。所有的奶牛名字不超过 10 个字符,且仅包含字符 a…z 或 A…Z。

由此可得,根据关系连边可以建出一棵树。

#include<bits/stdc++.h>
using namespace std;
#define MAXN 105
int n,by[MAXN];
map<string,int>dsc;
map<string,int>sgn;
struct nod{
	int to,val;
	nod(int t,int v):to(t),val(v){}
};
vector<nod>g[MAXN];
void ini(){//初始化
	by[1]=0;
	dsc["Bessie"]=1;
	sgn["Ox"]=0;
	sgn["Tiger"]=1;
	sgn["Rabbit"]=2;
	sgn["Dragon"]=3;
	sgn["Snake"]=4;
	sgn["Horse"]=5;
	sgn["Goat"]=6;
	sgn["Monkey"]=7;
	sgn["Rooster"]=8;
	sgn["Dog"]=9;
	sgn["Pig"]=10;
	sgn["Rat"]=11;
}int spfa(int fir,int tar){//树上距离可以O(n)求出,这里懒,直接spfa
	queue<int>spf;
	int dis[MAXN];
	bool vh[MAXN];
	spf.push(fir);
	memset(dis,63,sizeof(dis));dis[fir]=0;
	memset(vh,false,sizeof(vh));vh[fir]=true;
	while(!spf.empty()){
		int id=spf.front();
		spf.pop();
		vh[id]=false;
		for(int i=0;i<g[id].size();++i){
			int v=g[id][i].to,w=g[id][i].val;
			if(dis[id]+w<dis[v]){
				dis[v]=dis[id]+w;
				if(!vh[v]){
					spf.push(v);
					vh[v]=true;
				}
			}
		}
	}return dis[tar];
}
int main(){
	freopen("yearcow.in","r",stdin);
	freopen("yearcow.out","w",stdout);
	cin>>n;
	ini();
	string s[8];
	for(int i=1;i<=n;++i){
		for(int j=0;j<8;++j)
			cin>>s[j];
		dsc[s[0]]=i+1;
		by[i+1]=sgn[s[4]];
		int qian=i+1,hou=dsc[s[7]],val=-1;
		if(s[3][0]=='p'){
			if(by[qian]<by[hou])
				val=by[hou]-by[qian];
			else
				val=12-by[qian]+by[hou];
			g[qian].push_back(nod(hou,val));
			g[hou].push_back(nod(qian,-val));
		}else{
			if(by[qian]>by[hou])
				val=by[qian]-by[hou];
			else
				val=12-by[hou]+by[qian];
			g[qian].push_back(nod(hou,-val));
			g[hou].push_back(nod(qian,val));
		}if(s[0]=="Elsie"){
			cout<<abs(spfa(1,i+1))<<endl;
			break;
		}
	}fclose(stdin);
	fclose(stdout);
	return 0;
}
直接求:

给出关系,其中一个已知,另一个未知,由此可以求出未知的一个。

#include<bits/stdc++.h>
using namespace std;
#define MAXN 105
int n,by[MAXN],fy[MAXN];
map<string,int>dsc;
map<string,int>sgn;
void ini(){
	by[1]=0;
	dsc["Bessie"]=1;
	sgn["Ox"]=0;
	sgn["Tiger"]=1;
	sgn["Rabbit"]=2;
	sgn["Dragon"]=3;
	sgn["Snake"]=4;
	sgn["Horse"]=5;
	sgn["Goat"]=6;
	sgn["Monkey"]=7;
	sgn["Rooster"]=8;
	sgn["Dog"]=9;
	sgn["Pig"]=10;
	sgn["Rat"]=11;
}
int main(){
	freopen("yearcow.in","r",stdin);
	freopen("yearcow.out","w",stdout);
	cin>>n;
	ini();
	string s[8];
	for(int i=1;i<=n;++i){
		for(int j=0;j<8;++j)
			cin>>s[j];
		dsc[s[0]]=i+1;
		by[i+1]=sgn[s[4]];
		int qian=i+1,hou=dsc[s[7]],val=-1;
		if(s[3][0]=='p'){
			if(by[qian]<by[hou])
				val=by[hou]-by[qian];
			else
				val=12-by[qian]+by[hou];
			fy[qian]=fy[hou]-val;
		}else{
			if(by[qian]>by[hou])
				val=by[qian]-by[hou];
			else
				val=12-by[hou]+by[qian];
			fy[qian]=fy[hou]+val;
		}if(s[0]=="Elsie"){
			cout<<abs(fy[i+1])<<endl;
			break;
		}
	}fclose(stdin);
	fclose(stdout);
	return 0;
}

Problem 2. Comfortable Cows

Farmer John 的草地可以被看作是一个由正方形方格组成的巨大的二维方阵(想象一个巨大的棋盘)。初始时,草地上是空的。

Farmer John 将会逐一地将 N N N 1 ≤ N ≤ 1 0 5 1≤N≤10^5 1N105)头奶牛加入到草地上。第 i i i 头奶牛将会占据方格 ( x i , y i ) (x_i,y_i) (xi,yi),不同于所有已经被其他奶牛占据的方格( 0 ≤ x i , y i ≤ 1000 0≤x_i,y_i≤1000 0xi,yi1000)。

一头奶牛被称为是「舒适的」,如果它水平或竖直方向上与恰好三头其他奶牛相邻。Farmer John 对他的农场上舒适的奶牛数量感兴趣。对 1 … N 1…N 1N 中的每一个 i i i,输出第 i i i 头奶牛加入到草地上之后舒适的奶牛的数量。

输入格式(从终端 / 标准输入读入):

输入的第一行包含一个整数 N N N。以下 N N N 行每行包含两个空格分隔的整数,表示一头奶牛所在的方格坐标 ( x , y ) (x,y) (x,y)。输入保证所有方格的坐标是不同的。

输出格式(输出至终端 / 标准输出):

输出的第 i i i 行包含前 i i i 头奶牛加入到草地上之后舒适的奶牛的数量。

输入样例:
8
0 1
1 0
1 1
1 2
2 1
2 2
3 1
3 2
输出样例:
0
0
0
1
0
0
1
2

在前四头奶牛加入之后,位于 ( 1 , 1 ) (1,1) (1,1) 的奶牛是舒适的。

在前七头奶牛加入之后,位于 ( 2 , 1 ) (2,1) (2,1) 的奶牛是舒适的。

在前八头奶牛加入之后,位于 ( 2 , 1 ) (2,1) (2,1) ( 2 , 2 ) (2,2) (2,2) 的奶牛是舒适的。

测试点性质:
  • 测试点 1-4 满足 N ≤ 400 N≤400 N400
  • 测试点 5-12 没有额外限制。

供题:Benjamin Qi

分析:

哈希。

#include<bits/stdc++.h>
using namespace std;
#define MAXN 100010
#define MAXL 1010
int n,a[MAXN],num=0,vh[MAXL][MAXL];
void work(int id){
	++a[id];
	if(a[id]==3)//数量+1
		++num;
	if(a[id]==4)//4是从3加上去的,所以舒适的数量-1
		--num;
}
int main(){
	freopen("comfortable.in","r",stdin);
	freopen("comfortable.out","w",stdout);
	cin>>n;
	int x,y;
	for(int i=1;i<=n;++i){
		cin>>x>>y;
		++x,++y;
		vh[x][y]=i;
		if(vh[x-1][y]){//对周围4个位置的奶牛操作,同时计算自己周围的奶牛数量
			++a[i];
			work(vh[x-1][y]);
		}if(vh[x+1][y]){
			++a[i];
			work(vh[x+1][y]);
		}if(vh[x][y-1]){
			++a[i];
			work(vh[x][y-1]);
		}if(vh[x][y+1]){
			++a[i];
			work(vh[x][y+1]);
		}if(a[i]==3)
			++num;
		cout<<num<<endl;
	}fclose(stdin);
	fclose(stdout);
	return 0;
}

Problem 3. Clockwise Fence

围绕 Farmer John 最大的草地的栅栏已经损坏了,如今他终于决定要换一个新的栅栏。

不幸的是,当 Farmer John 在铺设新栅栏时,一只巨大的蜜蜂突然出现,在他的草地上追着他跑,导致最后栅栏被沿着一条相当不规则的路径铺设。栅栏可以用一个字符串表示,每个字符为 “N”(north,北)、“E”(east,东)、“S”(south,南)、“W”(west,西)之一。每个字符表示一米长的一段栅栏。举例来说,如果字符串为 NESW,这表示栅栏从起点开始向北延伸 1 米,然后向东延伸 1 米,然后向南延伸 1 米,然后向西延伸 1 米,回到栅栏的起点。

栅栏的结束位置与开始位置相同,而这是栅栏的路径上唯一会被到达多次的位置(从而起始位置是唯一会被再次到达的位置,在栅栏结束之时)。结果,栅栏确实围起了一个草地上连通的区域,尽管这个区域可能形状十分奇特。

Farmer John 想要知道他铺设栅栏的路径是顺时针(当按字符串表示的顺序沿着栅栏的路径行走时被围起的区域位于右侧)还是逆时针(被围起的区域位于左侧)。

输入格式(从终端 / 标准输入读入):

输入的第一行包含一个整数 N N N 1 ≤ N ≤ 20 1≤N≤20 1N20)。以下 N N N 行每行包含一个长度不小于 4 且不超过 100 的字符串,表示一个栅栏的路径。

输出格式(输出至终端 / 标准输出):

N N N 条输入的栅栏路径的每一条,输出一行,为 “CW”(clockwise,顺时针)或 “CCW”(counterclockwise,逆时针)。

输入样例:
2
NESW
WSSSEENWNEESSENNNNWWWS
输出样例:
CW
CCW

以下为这两条栅栏路径,用 @ 表示起始位置:

*>*
^ v
@<*

  *<*<*<*
  v     ^
*<@     *
v       ^
* *>*>* *
v ^   v ^
* *<* * *
v   ^ v ^
*>*>* *>*

供题:Brian Dean

分析:

①由题可得

顺时针(当按字符串表示的顺序沿着栅栏的路径行走时被围起的区域位于右侧)
逆时针(被围起的区域位于左侧)

则可以使用洪水填充。

②由于题意相当于,给出一个内角为 1 2 π \frac{1}{2}\pi 21π 3 2 π \frac{3}{2}\pi 23π 封闭图形,由此可以得到:该图形一定有一条或多条最靠左的边(向下左右均有)。
不难发现,顺时针行走时,最靠左的边方向一定向上,逆时针行走时,最靠左的边方向一定向下。

③无论如何,该图形 1 2 π \frac{1}{2}\pi 21π 的角一定比 3 2 π \frac{3}{2}\pi 23π 的要多 4 4 4 个。
一个矩形有 4 4 4 1 2 π \frac{1}{2}\pi 21π 的角,如果一个角向内“凹”,则会减少 1 1 1 个出现 2 2 2 1 2 π \frac{1}{2}\pi 21π 的角,并出现 1 1 1 3 2 π \frac{3}{2}\pi 23π 的角;如果一条边向内“凹”,则会出现 2 2 2 1 2 π \frac{1}{2}\pi 21π 的角和 2 2 2 3 2 π \frac{3}{2}\pi 23π 的角。“凸”同理。
所以顺时针行走时,右转次数比左转次数多 4 4 4 次,逆时针相反。

①略

e , w e,w e,w 分别表示当前已经向东向西各走了多少单位长,对两者差值打擂台可得最靠边的边(南北同理)。

#include<bits/stdc++.h>
using namespace std;
int n;
string s;
bool check(int len){
	int e=0,w=0,minn=114514;
	bool flag=false;
	for(int i=0;i<len;++i){
		if(s[i]=='E')
			++e;
		else if(s[i]=='W')
			++w;
		else
			if(e-w<minn){
				minn=e-w;
				flag=(s[i]=='N');
			}
	}return flag;
}
int main(){
	freopen("direction.in","r",stdin);
	freopen("direction.out","w",stdout);
	cin>>n;
	for(int i=1;i<=n;++i){
		cin>>s;
		if(check(s.length()))
			cout<<"CW"<<endl;
		else
			cout<<"CCW"<<endl;
	}fclose(stdin);
	fclose(stdout);
	return 0;
}
#include<bits/stdc++.h>
using namespace std;
int n;
string s,tr="NESWN";
int main(){
	cin>>n;
	for(int i=1;i<=n;++i){
		cin>>s;
		s+=s[0];
		int num=0;
		for(int j=0;j<s.length();++j){
			if(s[j]==s[j+1])//是否有转弯
				continue;
			if(tr[tr.find(s[j])+1]==s[j+1])//判断是否为顺时针
				++num;
			if(tr[tr.rfind(s[j])-1]==s[j+1])//判断是否为逆时针
				--num;
		}if(num>0)
			cout<<"CW"<<endl;
		else
			cout<<"CCW"<<endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值