CSP-WEEK12模拟赛(面向cspT1/T2/T4)

CSP-Week12 模拟赛

T1 签到题

题目叙述

瑞神的数学一向是最好的,连强大的咕咕东都要拜倒在瑞神的数学水平之下,虽然咕咕东很苦恼,但是咕咕东拿瑞神一点办法都没有。
5.1期间大家都出去玩了,只有瑞神还在孜孜不倦的学习,瑞神想到了一个序列,这个序列长度为n,也就是一共有n个数,瑞神给自己出了一个问题:数列有几段?
段的定义是位置连续的数值相同的最长整数序列

Input和输入样例:

输入第一行一个整数n,表示数的个数
接下来一行n个空格隔开的整数,表示不同的数字

12
2 3 3 6 6 6 1 1 4 5 1 4

Output和输出样例

输出一行,这个序列有多少段

8

思路叙述

简单的签到题,每次记录当前的数字,读到的和该数字相同就继续向下,不相同段数+1.。

实现代码

#include<iostream>
#include<stdio.h>
using namespace std;

const int M=1e5;
int main()
{
    
    
	int right=0;
	int now_num=M;
	int number;
	int piece=0;
	scanf("%d",&number); 
	for(int i=0;i<number;i++)
	{
    
    
		int each_num=0;
		scanf("%d",&each_num);
		if(each_num==now_num)
		{
    
    
			right++;
		}
		else
		{
    
    
			if(right>0)
			{
    
    
				piece++;
			}
			now_num=each_num;
			right=1;
		}
	 } 
	 if(right>0)
	{
    
    
		piece++;
	}
	 printf("%d\n",piece);
	return 0;
 } 

T2-消消乐大师——Q老师

题目简述

Q老师是个很老实的老师,最近在积极准备考研。Q老师平时只喜欢用Linux系统,所以Q老师的电脑上没什么娱乐的游戏,所以Q老师平时除了玩Linux上的赛车游戏SuperTuxKart之外,就是喜欢消消乐了。
游戏在一个包含有n行m列的棋盘上进行,棋盘的每个格子都有一种颜色的棋子。当一行或一列上有连续三个或更多的相同颜色的棋子时,这些棋子都被消除。当有多处可以被消除时,这些地方的棋子将同时被消除。
一个棋子可能在某一行和某一列同时被消除。
由于这个游戏是闯关制,而且有时间限制,当Q老师打开下一关时,Q老师的好哥们叫Q老师去爬泰山去了,Q老师不想输在这一关,所以它来求助你了!!

Input和输入样例

输入第一行包含两个整数n,m,表示行数和列数
接下来n行m列,每行中数字用空格隔开,每个数字代表这个位置的棋子的颜色。数字都大于0.

4 5
2 2 3 1 2
3 4 5 1 4
2 3 2 1 3
2 2 2 4 4

Output和输出样例

输出n行m列,每行中数字用空格隔开,输出消除之后的棋盘。(如果一个方格中的棋子被消除,则对应的方格输出0,否则输出棋子的颜色编号。)

2 2 3 0 2
3 0 0 0 0
2 3 2 0 3
2 2 0 0 0

解题思路

看起来稍微有点复杂,但是其实稍微思考下很简单的一道小模拟。首先将元素保存在访问矩阵中和输出矩阵中。遍历依次看横向的三个元素或者竖向三个元素,如果是相同的在输出矩阵中置为零即可,由于一列或一行上面元素大于三的情况一定可以分解成多个等于三的情况,遍历一遍整个数组就可以求出解。

实现代码

#include<iostream>
#include<stdio.h>
using namespace std;

const int M=32;
int origin[M][M];
int change[M][M];

int main()
{
    
    
	int m=0;
	int n=0;
	scanf("%d %d",&m,&n);
	for(int i=1;i<=m;i++)
	{
    
    
		for(int j=1;j<=n;j++)
		{
    
    
			int num=0;
			scanf("%d",&num);
			origin[i][j]=num;
			change[i][j]=num;
		}
	} 
	for(int i=1;i<=m;i++)
	{
    
    
		for(int j=2;j<=n-1;j++)
		{
    
    
			int num1=origin[i][j-1];
			int num2=origin[i][j];
			int num3=origin[i][j+1];
			if(num1==num2 && num2==num3)
			{
    
    
				change[i][j-1]=change[i][j]=change[i][j+1]=0;
			}
		}
	}
	for(int j=1;j<=n;j++)
	{
    
    
		for(int i=2;i<=m-1;i++)
		{
    
    
			int num1=origin[i-1][j];
			int num2=origin[i][j];
			int num3=origin[i+1][j];
			if(num1==num2 && num2==num3)
			{
    
    
				change[i-1][j]=change[i][j]=change[i+1][j]=0;
			}
		}
	 } 
	 for(int i=1;i<=m;i++)
	{
    
    
		for(int j=1;j<=n;j++)
		{
    
    
			if(j==n)
			printf("%d",change[i][j]);
			else
			printf("%d ",change[i][j]);
		}
		printf("\n");
	}
	 return 0;
}

T4-一道非典型回文串题目

题目叙述

咕咕东很聪明,但他最近不幸被来自宇宙的宇宙射线击中,遭到了降智打击,他的英语水平被归零了!这一切的始作俑者宇宙狗却毫不知情!

此时咕咕东碰到了一个好心人——TT,TT在吸猫之余教咕咕东学英语。今天TT打算教咕咕东字母A和字母B,TT给了咕咕东一个只有大写A、B组成的序列,让咕咕东分辨这些字母。

但是咕咕东的其他学科水平都还在,敏锐的咕咕东想出一个问题考考TT:咕咕东问TT这个字符串有多少个子串(由原字符串中位置连续的字符构成的字符串)是Delicious的。

TT虽然会做这个问题,但是他吸完猫发现辉夜大小姐更新了,不想回答这个问题,并抛给了你,你能帮他解决这个问题吗?

Delicious定义:对于一个字符串,我们认为它是Delicious的当且仅当它的每一个字符都至少属于一个长度大于1且被完整包含在这个字符串中的回文子串中。

我们说某个字符串是回文的,即这个字符串从左往右读和从右往左读是相等的。

子串(substring)的概念:比如 abc 是 ddddabcdddd 的子串。

下面是一些Delicious字符串的的例子:

t=AABBB (字符t1, t2属于回文串t1…t2, 字符t3, t4, t5属于回文串t3…t5)
t=ABAA (字符t1, t2,t3属于回文串t1…t3, 字符t3, t4属于回文串t3…t4)
t=AAAAA (所有字符均属于回文串 t1…t5)

Input和输入样例

输入第一行一个正整数n,表示字符串长度
接下来一行,一个长度为n只由大写字母A、B构成的字符串
输入样例:

5
AABBB

Output和输出样例

输出仅一行,表示符合题目要求的子串的个数。
输出样例:

6

思路概述

读了题目,你可能还是不太理解到底要求是什么啊???
为了方便理解题目和算法,用简单的话解释题目要求就是:求解该字符串中由回文子串拼接构成的子串个数,且要注意的是,这个拼接出的子串也要是原字符串的子串。
理解了题目,介绍两个解法,这两种解法受数据影响,在题目中会得到不同的分数:
尝试解法:暴力拼接
看了上述的要求,你的第一想法可能是:找到所有的回文子串,然后拼接并且判断是否属于就可以了。但是算算复杂度,好像有点高哎…粗略的计算一下,如果不适用剪枝等技巧,暴力的进行枚举判断所有子串,复杂度会飙到O(n^4),优化之后性能也很难太优,考试亲测基本只能得到40-60分,但是在没有其他思路时,也是得分的好办法。
正解:正繁反简
看着已经得到的分数,你可以能会很不甘心,再做各种优化,但基于一个复杂做法的优化往往很难达到正解的性能,我们不如换个思路。
固定长度的字符串,子串数量是固定的,因此如果能够计算出不符合要求的子串数量,使用总数量减去同样可以求出解。画几个样例分析下,可以发现不符合情况的子串只有下面四种情况:
1、AB…B
2、A…AB
3、B…BA
4、BA…A
总结一下就是,在看到连续的字串时,一旦出现A到B或B到A的转换,那么这个串就是不符合要求的。
根据这个原理,对输入样例AABBB可以做以解释:
从出现AB转换的位置找,A串部分不符合要求有AAB\AB,B串部分不符合要求的有ABB\ABBB,这里要注意的是,交界处的AB/BA只被计数一次,编码时需要加以注意。根据这种思路可以得到满分,时间性能更是优化到了惊人的O(n)。

T4实现源代码

#include<iostream>
#include<stdio.h>
using namespace std;

char last_c;
char now_c;
int last_pos;
int now_pos;
int number;
long long wrong_ans;
bool begin_flag=false;

int main()
{
    
    
    wrong_ans=0;
    last_pos=0;
    now_pos=0;
    scanf("%d",&number);
    getchar(); 
    scanf("%c",&last_c);
    for(int i=1;i<number;i++)
    {
    
    
        scanf("%c",&now_c);
        if(now_c!=last_c)//新输入的不同
        {
    
    
            while(last_pos!=now_pos)
            {
    
    
                wrong_ans++;
                last_pos++;
            }
            begin_flag=true;
        }
        else
        {
    
    
            now_pos++;
        }
        if(begin_flag==true)
        wrong_ans++;
        last_c=now_c;
    }
    printf("%lld",(1ll*number*(number-1))/2-wrong_ans);
}

猜你喜欢

转载自blog.csdn.net/qq_43942251/article/details/106084377