CSPM3

T1 瑞神的序列

题目描述

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

输入描述

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

输出描述

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

数据规模

数据点数据范围
<=1000<=1000

思路

遍历序列,利用一个变量t记录当前段的数值,如果遍历到的数a[i]与t不同,那么段数加1,t=a[i]。

需注意的点

最开始t应该初始化为一个序列中不可能出现的数。

完整代码

#include<iostream>
using namespace std;
int n;
int a[5000];
int t=1005;
int cnt;
int main ()
{
	cin>>n;
	for(int i=0;i<n;i++)	cin>>a[i];
	for(int i=0;i<n;i++)
	{
		if(a[i] != t)
		{
			cnt++;
			t=a[i];
		}
	}
	cout<<cnt<<endl;
	return 0;
} 

T2 消消乐大师——Q老师

题目描述

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

输入描述

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

输出描述

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

数据规模

nm颜色数字大小
<=30<=30<10

基本思路

本题的数据规模并不大,把棋盘存储在n x m二维数组a中,遍历一遍数组,找到所有会变为0的点,并将结果存在n x m的二维数组t中,然后输出按顺序t的元素即可。

对于二维数组中元素a[i][j],满足下列情况之一就应该变为0。

  • a[i-2][j],a[i-1][j]均合法,且a[i-2][j] = a[i-1][j] = a[i][j];
  • a[i-1][j],a[i+1][j]均合法,且a[i-1][j] = a[i][j] = a[i+1][j];
  • a[i+1][j],a[i+2][j]均合法,且a[i][j] = a[i+1][j] = a[i+2][j];
  • a[i][j-1],a[i][j-2]均合法,且a[i][j-2] = a[i][j-1] = a[i][j];
  • a[i][j-1],a[i][j+1]均合法,且a[i][j-1] = a[i][j] = a[i][j+1];
  • a[i][j+1],a[i][j+2]均合法,且a[i][j] = a[i][j+1] = a[i][j+2];

完整代码

#include<iostream>
using namespace std;
int n, m;
int a[50][50];
int t[50][50];
bool isvld(int i, int j)
{
	return (i>=1 && i<=n && j>=1 && j<=m);
}

bool can_clr(int i1, int j1, int i2, int j2, int i3, int j3)
{
	if(isvld(i1, j1) && isvld(i2, j2) && isvld(i3, j3))
	{
		if(a[i1][j1] == a[i2][j2] && a[i2][j2] == a[i3][j3])	return true;
	}
	return false;
}
int main ()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			cin>>a[i][j];
		}
	}
	
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			
				
			if(can_clr(i,j,i,j-1,i,j-2)  || 
			   can_clr(i,j,i,j-1,i,j+1)  ||
			   can_clr(i,j,i,j+1,i,j+2)  || 
			   can_clr(i,j,i-1,j,i-2,j)  || 
			   can_clr(i,j,i-1,j,i+1,j)  || 
			   can_clr(i,j,i+1,j,i+2,j))
				t[i][j] = 0;
			else	t[i][j] = a[i][j];
 		}
	}
	
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<m;j++)
		{
			cout<<t[i][j]<<" ";
		}
		cout<<t[i][m]<<endl;
	}
	return 0;
} 

T4 咕咕东学英语

题目描述

咕咕东很聪明,但他最近不幸被来自宇宙的宇宙射线击中,遭到了降智打击,他的英语水平被归 零了!这一切的始作俑者宇宙狗却毫不知情! 此时咕咕东碰到了一个好心人——TT,TT在吸猫之余教咕咕东学英语。今天TT打算教咕咕东字母A 和字母B,TT给了咕咕东一个只有大写A、B组成的序列,让咕咕东分辨这些字母。 但是咕咕东的其他学科水平都还在,敏锐的咕咕东想出一个问题考考TT:咕咕东问TT这个字符串 有多少个子串是Delicious的。 TT虽然会做这个问题,但是他吸完猫发现辉夜大小姐更新了,不想回答这个问题,并抛给了你, 你能帮他解决这个问题吗? Delicious定义:对于一个字符串,我们认为它是Delicious的当且仅当它的每一个字符都属于一个 大于1的回文子串中。

输入描述

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

输出描述

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

数据规模

n < = 3 × 1 0 5 n<=3\times10^5 n<=3×105

基本思路

题目中一个非常非常重要的条件是:字符串中只含有A,B两个字母。正是因为这个原因,只有AB,ABB,ABBB,… 和 BA,BAA,BAAA,…以及这些字符串的逆序列是不符合题目要求的字符串。

我们可以知道,子串的总数是 n ( n − 1 ) / 2 n(n-1)/2 n(n1)/2,只需统计不合法的字符串,用总数减去即可。

需要注意的点

  • 统计不合法的子串可以通过正反两次遍历得到,但是要注意的是,这样做"AB","BA"两个字符串被多统计了一次。
  • 计算 n ( n − 1 ) / 2 n(n-1)/2 n(n1)/2时要小心整形溢出。

完整代码

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int n;
string s;
char c;
int cnt;
char tmp(char c)
{
	return  (('B' - c) + 'A');
}

void add()
{
	c=s[0];
	for(int i=1;i<n;i++)
	{
		if(s[i] != c)	cnt += 1;
		else if(s[i-1] != s[i])
		{
			cnt += 1;
			c = tmp(c);
		}
	}
}	
int main ()
{
	cin>>n;
	cin>>s;
	add();
	reverse(s.begin(), s.end());
	add();
	for(int i=1;i<n;i++)
	{
		if((s[i-1] == 'A' && s[i] == 'B') 
			|| (s[i-1] == 'B' && s[i] == 'A'))
			cnt -= 1;
	}
	cout<< (long long)n*(n-1)/2 - cnt<<endl;
	
	return 0;
} 

补充: 统计不合法字符串的简单方法

  1. 识别出连续子串(如"AAA", "BBBB"等),检查其两侧是否有字符。
  2. AB、BA会被算两次,为了防止重复我们应该只考虑一次(仅仅在左侧有字符时考虑或者仅仅在右侧有字符时考虑)。

代码

#include <iostream> 
using namespace std;
int n;
char s[1000000];
int main ()
{
	cin>>n;
	cin>>s;
	long long ans = (long long)n * (n-1) / 2, l = 0;
	for(int i=0;s[i];i++)
	{
		if(s[l] != s[i+1])    //找到一段连续子串
		{
			if(s[i+1])	ans -= i-l;  //如果右侧有字符(不考虑BA或AB)
			if(l)	ans -= i-l+1;    //如果左侧有字符(考虑BA或AB)
			l = i+1; //寻找下一段连续子串
		}
	}
	cout<<ans<<endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值