zcmu-- 中医药院校程序设计竞赛备赛一【前缀和,博弈】

                                         目录

2959--Problem B: Amity Assessment【思维】

1986- Problem C: 周期串plus【周期】

1980-- Problem D: 不存在的泳池【最大公因数】

1907-- Problem E: k倍区间【前缀和优化】

1916-Problem F: E.当然是选择原谅你【博弈】

3037-Problem H:Block Towers【思维】


                          2959--Problem B: Amity Assessment

Description

Bessie the cow and her best friend Elsie each received a sliding puzzle on Pi Day. Their puzzles consist of a 2×2 grid and three tiles labeled 'A', 'B', and 'C'. The three tiles sit on top of the grid, leaving one grid cell empty. To make a move, Bessie or Elsie can slide a tile adjacent to the empty cell into the empty cell as shown below:

In order to determine if they are truly Best Friends For Life (BFFLs), Bessie and Elsie would like to know if there exists a sequence of moves that takes their puzzles to the same configuration (moves can be performed in both puzzles). Two puzzles are considered to be in the same configuration if each tile is on top of the same grid cell in both puzzles. Since the tiles are labeled with letters, rotations and reflections are not allowed.

Input

 The first two lines of the input consist of a 2×2 grid describing the initial configuration of Bessie's puzzle. The next two lines contain a 2×2 grid describing the initial configuration of Elsie's puzzle. The positions of the tiles are labeled 'A', 'B', and 'C', while the empty cell is labeled 'X'. It's guaranteed that both puzzles contain exactly one tile with each letter and exactly one empty position.

Output

 Output "YES"(without quotes) if the puzzles can reach the same configuration (and Bessie and Elsie are truly BFFLs). Otherwise, print "NO" (without quotes).

扫描二维码关注公众号,回复: 3372213 查看本文章

Sample Input

AB XC XB AC

Sample Output

YES

HINT

The solution to the sample is described by the image. All Bessie needs to do is slide her 'A' tile down.

 解题思路:这题说难也难说不难也不难,主要看我们怎么理解的。我们直到它只能逆时针或者顺时针转,然后发现只要把X去掉,就逆时针判断它是不是字串就好了,前面那个逆时针存储2遍非X的字母,然后下一组也逆时针旋转一遍非X的字母,之后判断它是不是前面的子串就好了,比赛的时候就一直旋转,但不知道怎么处理,赛后听了一个可爱的小姑凉的说法我就知道怎么处理了,如果还不懂的自己画个图或者看我下面的代码理解理解就好。

#include<bits/stdc++.h>
using namespace std;
char a[2][2],b[2][2],c[10],d[10];
int main(void)
{
	for(int i=0;i<2;i++)
	{
		for(int j=0;j<2;j++)
		{
			scanf("%c",&a[i][j]);
		}
		getchar();
	}
	
	for(int i=0;i<2;i++)
	{
		for(int j=0;j<2;j++)
		{
			scanf("%c",&b[i][j]);
		}
		getchar();
	}
	int k=0;
	for(int j=0;j<2;j++)
	{
		if(a[0][j]!='X')
		c[k++]=a[0][j];
	 } 
	for(int j=1;j>=0;j--)
	{
		if(a[1][j]!='X')
		c[k++]=a[1][j];
	 }
	for(int j=0;j<2;j++)
	{
		if(a[0][j]!='X')
		c[k++]=a[0][j];
	 } 
	for(int j=1;j>=0;j--)
	{
		if(a[1][j]!='X')
		c[k++]=a[1][j];
	 }
	//for(int i=0;i<strlen(c);i++) cout<<c[i];
	//cout<<endl;
	k=0;
	for(int j=0;j<2;j++)
	{
		if(b[0][j]!='X')
		d[k++]=b[0][j];
	} 
	for(int j=1;j>=0;j--)
	{
		if(b[1][j]!='X')
		d[k++]=b[1][j];
	 } 
	//for(int i=0;i<strlen(d);i++) cout<<d[i];
	//cout<<endl;
	if(strstr(c,d)!=0) cout<<"YES"<<endl;
	else cout<<"NO"<<endl;
	return 0;	
} 

                               1986- Problem C: 周期串plus

Description

如果一个字符串可以由某个长度为k的字符串重复多次得到,我们说该串以k为周期。例如abcabcabcabc以3为周期(当然他也以6,12为周期)。输入一个长度不超过100000的串,输出他的最小周期。

Input

多组测试数据,每组仅一行为一个仅有大写字母组成的字符串。

Output

对于每组数据输出该字符串的最小周期。

Sample Input

HOHO

Sample Output

2

解题思路:最小周期长度肯定是1到len,如果要是周期,那肯定是能够让len整除的,如果整除,就开始判断每一个对应的字符是否相等,一旦不等就退出循环,重新选一个长度,直到找到为止。余数在这里还是蛮好用的,我们如果找到能够让len整除的,就让j=i,开始后面判断s[j]是否等于s[j%i],如果不等直接退出循环,继续寻找。

#include<bits/stdc++.h>
using namespace std;  
const int maxn=1e5+5;
char s[maxn];
int main()  
{  
    
    int len ; 
    while(~scanf("%s",s))
    {
	  len=strlen(s);  
	  for (int i=1; i<=len; i++)  
	  {  
	       if (len%i==0)  
	       {  
	           bool flag=true;  
	           for (int j=i; j<len; j++)  
	           {  
	                if (s[j]!=s[j%i])  
	                {  
	                    flag=0;  
	                    break;  
	                }  
	            }  
	            if (flag)  
	            {  
	               cout<<i<<endl;  
	               break;  
	  
	            }  
	       }  
	    } 
	} 
    return 0;  
} 

                                        1980-- Problem D: 不存在的泳池

Description

小w是云南中医学院的同学,有一天他看到了学校的百度百科介绍:
截止到2014年5月,云南中医学院图书馆纸本藏书74.8457万册,纸质期刊388种,馆藏线装古籍图书1.8万册,电子资源总量35TB,拥有中、外文数据库25个,电子图书29.5万册(镜像)、包库130万册。古籍线装图书1.8万余册,有39种列为本馆珍善本,如《彻滕八编》、《赵氏医贯》等明清版本、台湾文渊阁版本《四库全书》,按《全国古籍善本书总目》分类表(即:经·史·子·集四部分类)部编列、上架、供读者使用。
显然学校图书馆的占地面积非常大,于是他开始想象.....如果他有一个跟图书馆一样大的游泳池?!
如果有一个那么大的游泳池,他就可以邀请女神一起去游泳...
如果有一个那么大的游泳池,他还可以划开一半出租,收取门票费赚钱...这样等赚了一些钱之后,就招一些游泳教练来,然后对外招生,招收学生继续赚更多的钱!
如果有一个那么大的游泳池,他还能把泳池里的水全部放光...开一个吕子乔心目中最大最棒的泳池派对!
.......
等有了更多的钱,就可以在第一个泳池旁边再建一个一样大的泳池......
小w一边流口水一边想自己的未来,一想到女神看到自己事业有成,靠一个游泳池白手起家发家致富,对自己投怀送抱,高兴的根本合不拢嘴。
这时候旁边的小q作为小w的室友,随口提了一句:“这么大的泳池,你怎么换水?”
显然小w是个有原则的人,他不会让自己的泳池像不法商家一样不换水,用不干净的水给别人使用或者给自己使用。
小w百度了之后发现...淘宝里有一家店卖一种一次性抽水机,这种一次性抽水机很神奇,它有两个按钮:
1.如果泳池里的水(立方米)是3的倍数,那么可以按第一个按钮让它抽走泳池里三分之二的水
2.如果泳池里的水(立方米)是2的倍数,那么可以按第二个按钮让它抽走泳池里二分之一的水
小w虽然是个有原则的人,但是作为一个商人,他需要节省钱...而且他现在有两个泳池....但是显然这种抽水机不能把水抽光,水越少,性价比就越低。
但是两个泳池建在一起,如果两个泳池的水面不一样高,那么小w会很不开心,所以他想用这种抽水机,把两个泳池里的水抽成一样多。然后再考虑别的....当然在保证能把两个泳池里的水抽成一样多的情况下..他希望花的钱最少...
(不管了!好看最重要,好看才能吸引顾客啊!先好看!再考虑怎么换水吧)

Input

多组测试数据,给出A,B表示两个泳池当前的水量(立方米)

(1<=A,B<=10^9)

Output

每组测试数据输出一个整数表示至少需要买多少个一次性抽水机,若买多少个都不能让泳池的水相等,则输出"-1"

Sample Input

5 20 14 8 6 6

Sample Output

2 -1 0

解题思路:一开始一脸懵,后面发现给出的泳池的值,如果要相等,就一定最后相同的是它们的最大公约数。我们先找出最大公约数,然后看一下他们的除以公约数的值一直除以3,2,直到2个值不能除为止,最后判断这2个整除公约数的值是不是等于1,如果都是就输出答案,要不然就输出-1。

#include<bits/stdc++.h>
using namespace std;
int gcd(int a,int b)
{
	if(a<b)
	swap(a,b);
	if(b) return gcd(b,a%b);
	return a;
}
int main(void)
{
	int a,b;
	while(~scanf("%d%d",&a,&b))
	{
		if(a==b) 
		{
			printf("0\n");
			continue;
		}
		int ans=gcd(a,b);
		int ans1=a/ans;
		int ans2=b/ans;
		int cnt=0;
		while(ans1%2==0) 
                { 
                    cnt++; 
                    ans1/=2; 
                } 
                while(ans1%3==0) 
                { 
                    cnt++; 
                    ans1/=3; 
                } 
                while(ans2%2==0) 
                { 
                    cnt++; 
                    ans2/=2; 
                } 
                while(ans2%3==0) 
                { 
                    cnt++; 
                    ans2/=3; 
                } 
                if(ans1==1&&ans2==1) 
                    printf("%d\n",cnt); 
                else
                    printf("-1\n"); 
        } 
	return 0;
}

    1907-- Problem E: k倍区间

Description

给定一个长度为N的数列,A1, A2, ... AN,如果其中一段连续的子序列Ai, Ai+1, ... Aj(i <= j)之和是K的倍数,我们就称这个区间[i, j]是K倍区间。

你能求出数列中总共有多少个K倍区间吗?

Input

每个数据包含多组输入数据

第一行包含两个整数N和K。(1 <= N, K <= 100000)
以下N行每行包含一个整数Ai。(1 <= Ai <= 100000)

Output

输出一个整数,代表K倍区间的数目。

Sample Input

5 2 1 2 3 4 5

Sample Output

6

解题思路:这题一看到就知道是前缀和,但是普通的前缀和需要2个循环O(n^2),肯定超时,所以需要优化。我们每次统计的是(sum[r]-sum[l-1])%k==0,我们知道sum[r]%k-sum[l-1]%k==0,也就是sum[r]%k和sum[l-1]%k的值要相同,所以我们每次统计我们当前取余的值的数量,同时这个值也要加加,最后我们不要忘了加上cnt[0]的值。可以根据下面我列出来的数据跟代码一个个核对,就会理解了。

第一个例子:sum[i]   i   sum[i]%2

                        1        1        1

                        3        2        1

                        6        3        0

                       10       4        0

                       15       5        1

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int sum[maxn],cnt[maxn];
int main(void)
{
	int n,k;
	while(~scanf("%d%d",&n,&k))
	{
		int x,ans=0;
		memset(cnt,0,sizeof cnt);
		memset(sum,0,sizeof sum);
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&x);
			sum[i]=(sum[i-1]+x)%k;//每次前缀和取余(1-i的和)
			ans+=cnt[sum[i]];//答案加上1到i之间的相同余数的数量
			cnt[sum[i]]++;
		}
		printf("%d\n",ans+cnt[0]);//cnt[0]不能忘了
	}
	return 0;
}

                                      1916- Problem F: E.当然是选择原谅你

Description

        最近HX无所事事,他的脑海里出现了一个想法。这个游戏盘的大小是n*m。首先,硬币放在右上角(1,m)。 每次有人可以将硬币移动到左边,下面或左下方的空白处。不能移动的人将失去游戏。 HX只能无聊到找XH玩了。游戏总是从HX开始。 如果两人都玩得很好,谁能赢得比赛呢?

Input

多组输入,直到输入0 0结束。

输入n和m(1 ≤ n ≤ 10^6)表示游戏盘的长与宽。

Output

如果HX赢则输出H,否则输出X。

Sample Input

5 3 5 4 0 0

Sample Output

X H

 解题思路:在画的时候就会发现规律,只要行和列都是奇数就是X赢,其他情况都是Y赢。

#include<bits/stdc++.h>
using namespace std;
int main(void)
{
	int n,m;
	while(~scanf("%d%d",&n,&m))
	{
		if(n==0&&m==0)
		break;
		if(m%2==1&&n%2==0) printf("X\n");
		else  printf("H\n");
	}
	return 0;
}

                                           3037-Problem H: Block Towers

Description

Students in a class are making towers of blocks. Each student makes a (non-zero) tower by stacking pieces lengthwise on top of each other. n of the students use pieces made of two blocks and m of the students use pieces made of three blocks.

The students don’t want to use too many blocks, but they also want to be unique, so no two students’ towers may contain the same number of blocks. Find the minimum height necessary for the tallest of the students' towers.

Input

 The first line of the input contains two space-separated integers n and m (0≤n,m≤1000000, n+m>0)− the number of students using two-block pieces and the number of students using three-block pieces, respectively.

Output

 Print a single integer, denoting the minimum possible height of the tallest tower.

Sample Input

1 3

Sample Output

9

HINT

 In the first case, the student using two-block pieces can make a tower of height 4, and the students using three-block pieces can make towers of height 3, 6, and 9 blocks. The tallest tower has a height of 9 blocks.

解题思路:这题读懂题意就会做了,主要是题意在比赛的时候没看懂,等到赛后问其他人才知道的。n是代表n个人用高度为2的堆塔,m是代表m个人用高度为3的堆塔,但每个人堆的塔的高度不能相同,然后求n+m个人中堆的塔的最高的那个高度的最小值,这句话有点难理解,我举个例子来理解这句话。假设n为4,m为3。4个人堆的高度:2,4,6,8,3个人堆的高度为3,6,9,可以发现6重复了,那我们就要分成2种处理6的方式。一让高度为2的6去掉,就变成10,二让高度为3的6去掉,就变成12,但我们要求最小值,所以我们选择10,总体发现只要是6的倍数,是6的几倍就有几个重复,其他3的倍数都是奇数不会与高度为2的相同,就只有6的倍数会。具体见代码。

#include<bits/stdc++.h>
using namespace std;
int main(void)
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        int x=n*2;
        int y=m*3;
        int i=6;
        while(i<=min(x,y))
        {
            if(x<y) x+=2;
            else y+=3;
            i+=6; 
        }
        printf("%d\n",max(x,y));
    }
    return 0;
}

                                

猜你喜欢

转载自blog.csdn.net/Imagirl1/article/details/82756588