纪中周末训练 2020.05.23【NOIP提高组】模拟 反思+题解

80分,39名,为啥一堆大佬来提高模拟虐菜!!!!

T1:【USACO 2017 US Open Silver】Problem 2.Bovine Genomics

Description

FJ有n头有斑点的牛和n头没有斑点的牛。由于他刚刚学完牛的基因学的课程,他想知道牛有没有斑点是否与牛的基因有关。
FJ花了巨大的代价测出了每个牛的基因,每头牛的基因用一个长度为M的由“A,C,G,T”的串构成。FJ将这些串写成一个表/矩阵,就像图中这样(N=3的例子)
在这里插入图片描述
FJ仔细的观察这个表,他发现通过观测2,4位置的字符串可以预测牛是否有斑点。
(在这个例子中,假如他看到24位置是GC、AT或者AC就可以断定其有斑点,因为1号有斑点的牛24位置基因为AC,2号为AT,3号为GC,而且没有任何一头无斑点的牛的24位置出现过这三个串)。
FJ认为,1个或者两个位点是不能够区分品种的,必须是刚好3个位点。他想知道能用多少组三个本质不同的位置判断牛的斑点,{1,2,3}和{1,3,2}是本质相同的

Input

The first line of input contains N ( 1 ≤ N ≤ 500 ) and M ( 3 ≤ M ≤ 50 ). The next N lines each contain a string of M characters; these describe the genomes of the spotty cows. The final N lines describe the genomes of the plain cows.

Output

Please count the number of sets of three distinct positions that can explain spottiness. A set of three positions explains spottiness if the spottiness trait can be predicted with perfect accuracy among Farmer John’s population of cows by looking at just those three locations in the genome.

Sample Input

3 8
AATCCCAT
GATTGCAA
GGTCGCAA
ACTCCCAG
ACTCGCAT
ACTTCCAT

Sample Output

22

反思&题解

比赛思路: 暴力枚举每三个点,之后再二重循环判断。
正解思路: 一样枚举三个点,判断的时候用一个标记数组判断就行了
反思: 考试的时候其实我想到了正解,但是因为思路不清晰否定掉。了,认为这样判断根本判断不出来

CODE

#include<bits/stdc++.h>
using namespace std;
int n,m,a[505][55],b[505][55],ans;
bool bz[55][55][55];
int main()
{
	scanf("%d%d",&n,&m);
	int i,j;
	char s[55];
	for (i=1;i<=n;i++)
	{
		scanf("%s",s+1);
		for (j=1;j<=m;j++)
		{
			if (s[j]=='A') a[i][j]=1;
			else if (s[j]=='C') a[i][j]=2; 
			else if (s[j]=='G') a[i][j]=3;
			else if (s[j]=='T') a[i][j]=4;
		}
	}
	for (i=1;i<=n;i++)
	{
		scanf("%s",s+1);
		for (j=1;j<=m;j++)
		{
			if (s[j]=='A') b[i][j]=1;
			else if (s[j]=='C') b[i][j]=2;
			else if (s[j]=='G') b[i][j]=3;
			else if (s[j]=='T') b[i][j]=4;
		}
	}
	int k,w;
	bool bz1;
	for (i=1;i<=m-2;i++)
	{
		for (j=i+1;j<=m-1;j++)
		{
			for (k=j+1;k<=m;k++)
			{
				bz1=true;
				memset(bz,false,sizeof(bz));
				for (w=1;w<=n;w++)
				{
					bz[a[w][i]][a[w][j]][a[w][k]]=true;	
				}
				for (w=1;w<=n;w++)
				{
					if (bz[b[w][i]][b[w][j]][b[w][k]])
					{
						bz1=false;
						break;
					}
				}	
				if (bz1) ans++;
			}	
		}
	}
	printf("%d\n",ans);
	
	return 0;
}

T2:【USACO 2017 US Open Silver】Problem 3.Where’s Bessie?

Description

农夫John正在测试一个他新发明的全自动寻找奶牛无人机,它能够照一张农场的图片然后自动找出奶牛的位置。不幸的是,这个相机并不包含一个优秀的寻找奶牛函数,所以农夫John需要你来写一个。农场的俯瞰图被定义为一个n * n的字符矩阵。矩阵由大写字母A到Z组成,每个字母表示一种可行的颜色。农夫John发现一个可能是奶牛的位置(以下简称PCL)的最好定义如下:一个PCL是一个矩阵(可能是整张图),矩阵的边与图像的边缘平行,且不能被其他PCL所包含(因此PCL内部不可能有PCL)更多的,一个PCL必须满足以下特性:1、矩阵有且只能有2种颜色构成。2、这两种颜色一种构成一个连通块,另一种形成两个或两个以上的连通块。举个例子:
AAAAA
ABABA
AAABB
这个矩阵就是一个PCL,其中颜色A构成一个连通块,B构成两个连通块,描述了一只可能以A为底色,B为花纹的奶牛。在这里连通块被定义为:从其中的任何一个点,你能仅通过上下左右移动,到达另外任何一个点(即上下左右相邻)给定农场的照片,请你计算图中有几个PCL。

Input

The first line of input contains N , the size of the grid ( 1 ≤ N ≤ 20 ). The next N lines describe the image, each consisting of N characters.

Output

Print a count of the number of PCLs in the image.

Sample Input

4
ABBC
BBBC
AABB
ABBC

Sample Output

2

Hint

In this example, the two PCLs are the rectangles with contents

ABB
BBB
AAB
ABB

and

BC
BC
BB
BC

反思&题解

正解思路: 暴力枚举每一个矩形,搜索相同数字的联通块,之后再判断是否被其他PCL包含。
反思: 又是一道想到正解的题,考试的时候调了很久都没发现哪儿错了,考完试之后问了大佬才知道我判断是否被包含的地方不该那样打。

CODE

#include<bits/stdc++.h>
using namespace std;
int a[25][25],n,ans=0,tot=0,bz[25][25];
struct arr
{
    int X1,X2,Y1,Y2;
}b[100005];
void find(int k,int i,int j,int xx,int xx2,int yy,int yy2)
{
    bz[i][j]=1;
    if (i<xx2 && bz[i+1][j]==0 && a[i+1][j]==k) find(k,i+1,j,xx,xx2,yy,yy2);
    if (j<yy2 && bz[i][j+1]==0 && a[i][j+1]==k) find(k,i,j+1,xx,xx2,yy,yy2);
    if (i>xx && bz[i-1][j]==0 && a[i-1][j]==k) find(k,i-1,j,xx,xx2,yy,yy2);
    if (j>yy && bz[i][j-1]==0 && a[i][j-1]==k) find(k,i,j-1,xx,xx2,yy,yy2);
    return;
}

bool check(int xx,int xx2,int yy,int yy2)
{
	int ltk[1005],sum=0,d[100005];
    memset(bz,0,sizeof(bz));
    memset(ltk,0,sizeof(ltk));
    memset(d,0,sizeof(d));
    int i,j;
    for (i=xx;i<=xx2;i++)
        for (j=yy;j<=yy2;j++)
        	if (bz[i][j]==0)
        	{
            	if (ltk[a[i][j]]==0)
				{
					sum++;
					d[sum]=a[i][j];
				}
            	if (sum>2) return false;
            	ltk[a[i][j]]++; 
            	find(a[i][j],i,j,xx,xx2,yy,yy2);
        	}   
    if (ltk[d[1]]==1 && ltk[d[2]]>1 || ltk[d[2]]==1 && ltk[d[1]]>1) return true;
    else return false;
}
bool pd(int x)
{
	int i;
    for (i=1;i<=tot;i++)
    {
        if (i!=x && b[x].X1>=b[i].X1 && b[x].X2<=b[i].X2 && b[x].Y1>=b[i].Y1 && b[x].Y2<=b[i].Y2) return false;
    }
    return true;
}

int main()
{
    scanf("%d",&n);
    char s[25];
    int i,j;
    for (i=1;i<=n;i++)
    {
    	scanf("%s",s+1);
		for (j=1;j<=n;j++)
			a[i][j]=s[j]-'A'+1;	
	}
	int k,v;
    for (i=1;i<=n;i++)
        for (j=i;j<=n;j++)
            for (k=1;k<=n;k++)
                for (v=k;v<=n;v++)
                    if (check(i,j,k,v))
					{
                        tot++;
                        b[tot].X1=i;
                        b[tot].X2=j;
                        b[tot].Y1=k;
                        b[tot].Y2=v;
                    }
    for (i=1;i<=tot;i++)
        if (pd(i)) ans++;
    printf("%d\n",ans);
    return 0;
}

T3:【USACO 2017 US Open Platinum】Problem 1 Modern Art

Description

小TY突然想画画,他有独特的艺术风格,他从N×N空白画布开始,其中0表示画布的空单元格。然后他会在画布上绘制恰好矩形,每个颜色是1到N×N中的一个。他每次可以选择任意一种未使用过的颜色进行绘画。例如,他可以从颜色2的矩形开始,画出这样的画布:

2 2 2 0

2 2 2 0

2 2 2 0

0 0 0 0

然后他可以用颜色7绘制一个矩形:

2 2 2 0

2 7 7 7

2 7 7 7

0 0 0 0

然后他可以在颜色3上绘制一个小矩形:

2 2 3 0

2 7 3 7

2 7 7 7

0 0 0 0

每个矩形都平行于画布边缘,而且矩形可以与整个画布一样大或者像一个单元一样小。每个颜色从1到正好使用一次,后来的颜色可能完全覆盖一些较早画上的颜色。

现在已知画布的最终状态,请计算有多少种颜色可能被第一个被画。

Input

The first line of input contains N , the size of the canvas ( 1 ≤ N ≤ 1000 ). The next N lines describe the final picture of the canvas, each containing N integers that are in the range 0 … N^2 . The input is guaranteed to have been drawn as described above, by painting successive rectangles in different colors.

Output

Please output a count of the number of colors that could have been drawn first.

Sample Input

4
2 2 3 0
2 7 3 7
2 7 7 7
0 0 0 0

Sample Output

14

Hint

In this example, color 2 could have been the first to be painted. Color 3 clearly had to have been painted after color 7, and color 7 clearly had to have been painted after color 2. Since we don’t see the other colors, we deduce that they also could have been painted first.

反思&题解

正解思路: 暴力枚举每一个 n 2 n^2 中的数字,判断如果这个数字盖过了其他的数字那么则将 a n s + + ans++ ,最后答案就是 n 2 a n s n^2-ans
注意: 有一个特判,如果这个输入矩阵的数字全部相同,那么答案则是 n 2 1 n^2-1
反思: 再前面两题浪费太多时间了,这题就没时间打了,只粗略地看了看题。

CODE

#include<bits/stdc++.h>
using namespace std; 
int a[1005][1005],l1[1000005],l2[1000005],r1[1000005],r2[1000005],n,ans;
bool bz[1000005];
int main()
{
	scanf("%d",&n);
	int tot=0;
	bool flag=true,flag2=true;
	flag=true;
	flag2=true;
	memset(l1,0x3f3f3f3f,sizeof(l1));
	memset(l2,0x3f3f3f3f,sizeof(l2));
	memset(r1,0,sizeof(r1));
	memset(r2,0,sizeof(r2));
	int i,j;
	for (i=1;i<=n;i++)
	{
		for (j=1;j<=n;j++)
		{
			scanf("%d",&a[i][j]);
			if (a[i][j]!=0)
			{
				if (flag)
				{
					tot=a[i][j];
					flag=false;
				}
				else if (tot!=a[i][j]) flag2=false;
			}
			l1[a[i][j]]=min(l1[a[i][j]],i);
			l2[a[i][j]]=min(l2[a[i][j]],j);
			r1[a[i][j]]=max(r1[a[i][j]],i);
			r2[a[i][j]]=max(r2[a[i][j]],j);
		}
	}
	int k;
	if (flag2)
	{
		printf("%d\n",n*n-1);
		return 0;
	}
	for (i=1;i<=n*n;i++)
	{
		if (r1[i]!=0 && r2[i]!=0)
		{
			for (j=l1[i];j<=r1[i];j++)
			{
				for (k=l2[i];k<=r2[i];k++)
				{
					if (a[j][k]!=i && !bz[a[j][k]])
					{
						bz[a[j][k]]=true;
						ans++;
					}
				}
					
			}
		}
	}
	printf("%d",n*n-ans);
}

猜你喜欢

转载自blog.csdn.net/CMC_YXY/article/details/106388597