20221126测试赛

20221126测试赛

T1-孤独照片(lonelyphoto)

时间限制:1.0s 内存限制:256.0MB
输入文件名:lonelyphoto.in 输出文件名:lonelyphoto.out
试题来源:USACO
问题描述
Farmer John 最近购入了 N 头新的奶牛(),每头奶牛的品种是更赛牛(Guernsey)或荷斯坦牛(Holstein)之一。

奶牛目前排成一排,Farmer John 想要为每个连续不少于三头奶牛的序列拍摄一张照片。 然而,他不想拍摄这样的照片,其中只有一头牛的品种是更赛牛,或者只有一头牛的品种是荷斯坦牛——他认为这头奇特的牛会感到孤立和不自然。 在为每个连续不少于三头奶牛的序列拍摄了一张照片后,他把所有「孤独的」照片,即其中只有一头更赛牛或荷斯坦奶牛的照片,都扔掉了。

给定奶牛的排列方式,请帮助 Farmer John 求出他会扔掉多少张孤独的照片。如果两张照片以不同的奶牛开始或结束,则认为它们是不同的。

输入格式
输入的第一行包含 N。

输入的第二行包含一个长为 N 的字符串。如果队伍中的第 i 头奶牛是更赛牛,则字符串的第 i 个字符为 G。否则,第 i 头奶牛是荷斯坦牛,该字符为 H。

输出格式
输出 Farmer John 会扔掉的孤独的照片数量。

输入样例
5
GHGHG
None
输出样例
3
None
样例说明
这个例子中的每一个长为 3 的子串均恰好包含一头更赛牛或荷斯坦牛——所以这些子串表示孤独的照片,并会被 Farmer John 扔掉。所有更长的子串(GHGH、HGHG 和 GHGHG)都可以被接受。

测试点性质
测试点 2-4 满足 N≤50。

测试点 5-10 满足 N≤5000。

为了增加一些挑战,测试点 11 没有额外限制。注意这个测试点的答案可能无法用标准的 32 位整数型存储,你可能需要使用更大的整数类型(例如,C++ 中 64 位的 “long long int” 类型)。

题目出处
看起来挺难的样子……

方法1:暴力枚举,三层循环O(n^3)算法。

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

long long n,ans;
char s[500010];

int main(){
	freopen("lonelyphoto.in","r",stdin);
	freopen("lonelyphoto.out","w",stdout); 
	cin>>n;
	for(long long i=1;i<=n;++i)cin>>s[i];
	for(long long i=1;i<=n-2;++i){//枚举左端点
		for(long long j=i+2;j<=n;++j){//枚举右端点 
			long long cowG=0,cowH=0;
			for(long long k=i;k<=j;++k){//统计H与G个数 
				if(s[k]=='G')++cowG;
				else ++cowH;
        	}
        		if(cowG==1||cowH==1)
				++ans;//为孤独照片 
		}
	}
	cout<<ans<<endl;
	fclose(stdin);
	fclose(stdout);
   	return 0;
}

实测36分。

方法2:采用前缀和优化,复杂度O(n^2)

采用前缀和优化可以避免循环过多。

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

char s[500010];
long long n,ans=0,g[500010],h[500010];


int main(){
	freopen("lonelyphoto.in","r",stdin);
	freopen("lonelyphoto.out","w",stdout);
	cin>>n;
	for(long long i=0;i<n;++i)cin>>s[i];
	if(s[0]=='G'){
		g[1]=1;
		h[1]=0;
	}
	else{
		g[1]=0;
		h[1]=0;
	}
	for(long long i=2;i<=n;++i){//前缀和
		if(s[i-1]=='G'){
			g[i]=g[i-1]+1;
			h[i]=h[i-1];
		}	
		else if(s[i-1]=='H'){
			g[i]=g[i-1];
			h[i]=h[i-1]+1;
		}
	}
	for(long long i=1;i<=n-2;++i){
		for(long long j=i+2;j<=n;++j){
			long long ansg=g[j]-g[i-1],ansh=h[j]-h[i-1];//根据前缀和算出当前牛的个数
			if(ansg==1||ansh==1)
				++ans;
		}
	}
	cout<<ans<<endl;
	fclose(stdin);
	fclose(stdout);
   	return 0;
}

90分

方法3:经分析,O(n)。

对于每一个点,统计出其上一个和下一个的G与H的位置。
1.当前牛种类及其最近相同种类里包含了其他种类且足够:合法数量为当前位置-上一个相同种类位置+1。
2.当前牛种类及其最近相同种类里包含了其他种类但不够:合法数量为当前位置-上上个H的位置+1。
3.一定区域内,牛种类一样:为当前位置-上上个H的位置+1-(上个G-上个H的位置)。

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

void check(int G[],int H[],int G2[],int H2[]);//函数声明
int n;
long long ans=0;
string s;

void readp(){
	cin>>n>>s;
}

void work(){
	int ansG=n,ansH=n,G[500010],H[500010],G2[500010],H2[500010];
	G[n]=G[n+1]=H[n]=H[n+1]=n;
	for(int i=n-1;i>=0;--i){
		if(s[i]=='G')ansG=i;
		else ansH=i;
		G[i]=ansG;//G数组记录当前位置之后第一个G出现的位置
		H[i]=ansH;//H数组记录当前位置之后第一个H出现的位置 
	}
	for(int i=n-1;i>=0;--i){
		G2[i]=G[G[i]+1];//G2记录第二个G
		H2[i]=H[H[i]+1];//H2记录第二个H
	}//O(n)预处理 
	check(G,H,G2,H2);//有递归的感觉了,嘿嘿
}

void check(int G[],int H[],int G2[],int H2[]){
	for(int i=0;i<n;++i){
		ans+=max(0,G2[i]-max(G[i],i+2));
		ans+=max(0,H2[i]-max(H[i],i+2));//i+2是长度最小为3,若下个G,H在i+2之外,即长度为3及以上的串里必含有2及以上个G,H,0防止负数 
	}
	cout<<ans<<endl;//输出
}

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

100分

T2-牧人游戏(herdle)

时间限制:1.0s 内存限制:256.0MB
输入文件名:herdle.in 输出文件名:herdle.out
试题来源:UASCO
问题描述
奶牛们发明了一种名为 Herdle 的新型解谜游戏,在牛界引起了轰动。

每天都会有一个新谜题发布供奶牛解决。游戏采用 3x3 方阵的形式表示农场的一块田地,田地的每个方格都由特定品种的奶牛占据。总共只有 26 种可能的品种,每一种由 A 到 Z 中的不同大写字母标识。玩家不会被告知田地中的奶牛品种排列方式——游戏目标是通过一系列猜测确定它们。

每次猜测,奶牛们输入一个 3x3 的大写字母方阵,表示该田地可以用奶牛填充的可能方式。猜测的某些方格可能是正确的。这些方格以绿色高亮显示,让奶牛们知道这些是正确的。猜测的另一些方格可能填入了品种正确但位置错误的奶牛。这些以黄色高亮显示。

黄色高亮显示的方格的数量可以帮助指示某个品种的奶牛数量。 例如,假设猜测方阵包含 4 头品种 A 的奶牛,而答案方阵包含 2 只品种 A 的奶牛,其中没有正确位置上的 A (即,它们都不应该是绿色的)。 在这种情况下,猜测方阵中只有两个 A 应以黄色高亮显示。 更准确地说,如果猜测方阵中有 x 个特定品种的奶牛,并且 答案方阵中有 y<x 头该品种奶牛(不包括位置正确而得到绿色高亮显示的奶牛),那么猜测方阵的 x 头奶牛中只有 y 头奶牛应该以黄色高亮显示。

给定正确答案的方阵和一个表示对该答案的猜测的方阵,请计算绿色和黄色高亮显示的方格的数量。

输入格式
输入的前 3 行给定了正确答案的方阵。以下 3 行表示对该答案的猜测。

输出格式
输出两行。

输出的第一行包含应当以绿色高亮显示的方格的数量。

输出的第二行包含应当以黄色高亮显示的方格的数量。

输入样例1
COW
SAY
MOO
WIN
THE
IOI
None
输出样例1
1
1
None
样例说明1
在这个例子中,最后一行中间的 O 是正确的,所以这个方格以绿色高亮显示。字母 W 位于错误的位置,所以它以黄色高亮显示。

输入样例2
AAA
BBB
CCC
AYY
AAA
ZZZ
None
输出样例2
1
2
None
样例说明2
在这里,其中一个 A 位于正确的位置,所以它以绿色高亮显示。余下的 A 均不在正确位置上,由于答案方阵中有两个 A,所以有两个 A 应当以黄色高亮显示。

题目出处
首先,这题目非常的良心(基本(3*3字符数组)不用考虑时间复杂度了),但是为了方便,还是用数组存。
题目大概意思就是:如果上下字符位置及内容一样,则一个绿色高亮;如果内容一致但位置不同,则黄色高亮。
但是,得明白一个问题:

“并且 答案方阵中有 y<x 头该品种奶牛(不包括位置正确而得到绿色高亮显示的奶牛),那么猜测方阵的 x 头奶牛中只有 y 头奶牛应该以黄色高亮显示。”

如果y>x呢???
answer:取x。
其实不就是取最小值吗?啰里啰嗦说了一大堆就是这个意思。
这个黄色高亮就可以统计一下解决。。。
代码:

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

char a[5][5],b[5][5];
int n[30],m[30],green,yellow; 

void readp(){
	for(int i=1;i<=3;++i)
		for(int j=1;j<=3;++j)
			cin>>a[i][j];
	for(int i=1;i<=3;++i)
		for(int j=1;j<=3;++j)
			cin>>b[i][j];
}

void check(){
	for(int i=1;i<=3;++i)
		for(int j=1;j<=3;++j)
			if(b[i][j]==a[i][j])green++;
			else{
				n[a[i][j]-'A']++;//统计数量
				m[b[i][j]-'A']++;
			}
	for(int i=0;i<26;++i){
		if(n[i]&&m[i]){
			int find=min(m[i],n[i]);//取最小值
			yellow+=find;
		}
	}
}

void print(){
	cout<<green<<endl;
	cout<<yellow<<endl;
}

int main(){
	freopen("herdle.in","r",stdin);
	freopen("herdle.out","w",stdout);
	readp();//输入
	check();
	print();//输出
	fclose(stdin);
	fclose(stdout);
	return 0;
}
posted @ 2022-12-05 10:20  whznfy  阅读(9)  评论(0)    收藏  举报  来源