CSP M3

T1 瑞神的序列

瑞神的數學一向是最好的,連強大的咕咕東都要拜倒在瑞神的數學水平之下,雖然咕咕東很苦惱,但是咕咕東拿瑞神一點辦法都沒有。 5.1期間大家都出去玩了,只有瑞神還在孜孜不倦的學習,瑞神想到了一個序列,這個序列長度爲 n,也就是一共有 n個數,瑞神給自己出了一個問題:數列有幾段? 段的定義是連續的相同的最長整數序列。

輸入

輸入第一行一個整數n,表示數的個數。
接下來一行n個空格隔開的整數,表示不同的數字。

輸出

輸出一行,這個序列有多少段 。

樣例輸入

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

樣例輸出

8

思路

綜述

題目是要求解一組數中,有幾個段,對於某一段,必須連續且數值相等;
比較簡單,用O(n)複雜度,掃一遍就可以;

想到另一個思路,(非本代碼思路)
倒着從後往前掃描;
如果後一個變量和前面的不一樣則總段數就++;最後再++;

想到一個點,如果輸入的數據爲0個,那就輸出0,不知道有沒有這樣的數據,反正檢驗一下不會錯。

代碼

#include <iostream>
using namespace std;
int n;
int a[1050];
int main(){
	cin>>n;
	int term;
	int cnt = 0 ; 
	for(int i=0;i<n;i++){
		cin>>a[i];
	}
	if(n==0)cout<<cnt<<endl;
	else{
		term = a[0];
		cnt++;
		for(int i=1;i<n;i++){
			if(a[i]==term)continue;
			else{
				term = a[i];
				cnt++;
			}
		}
		cout<<cnt<<endl;
	}
}

T2 消消樂大師——Q老師

Q老師是個很老實的老師,最近在積極準備考研。Q老師平時只喜歡用Linux系統,所以Q老師的電 腦上沒什麼娛樂的遊戲,所以Q老師平時除了玩Linux上的賽車遊戲SuperTuxKart之外,就是喜歡消消樂了。 遊戲在一個包含有 n 行 m 列的棋盤上進行,棋盤的每個格子都有一種顏色的棋子。當一行或一列 上有連續三個或更多的相同顏色的棋子時,這些棋子都被消除。當有多處可以被消除時,這些地方的棋子將同時被消除。 一個棋子可能在某一行和某一列同時被消除。 由於這個遊戲是闖關制,而且有時間限制,當Q老師打開下一關時,Q老師的好哥們叫Q老師去爬泰山去了,Q老師不想輸在這一關,所以它來求助你了!!

輸入

輸入第一行包含兩個整數n,m,表示行數和列數 ,接下來n行m列,每行中數字用空格隔開,每個數字代表這個位置的棋子的顏色。數字都大於0。

輸出

輸出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

樣例輸出

2 2 3 0 2 
3 4 5 0 4
2 3 2 0 3 
0 0 0 4 4

思路

哎,這個題做的真狼狽。最後輸出的時候,每一行最後沒有刪除空格,直接爆零;

綜述

定義兩個二維數組,
a用於存儲原始數據;
b數組用於存儲某個位置是否被消除。
由於數據量不大,所以針對每一個(i,j)位置的數;
往四個方向(上下左右)分別走一遍。

	to_up(i,j);
	to_down(i,j);
	to_left(i,j);
	to_right(i,j);
對某一個方向

以向右爲例;
記錄加上位置開始向右連續的有幾個相同的數共cnt個;
如果cnt>=3則b數組對應的位置標記一下,代表刪除;

void to_right(int i,int j){
	int x = i;
	int y = j;
	int term = a[i][j];
	int cnt = 1;
	while(1){
		y++;
		if(y>m)break;
		if(a[x][y]==term)cnt++;
		if(a[x][y]!=term)break;
	}
	if(cnt>=3){
		for(int y = j;y < m; y++){
			b[x][y] = 0;
			cnt--;
			if(cnt==0)break;
		}
	}
}

總結:

四個方向其實不用寫四個函數,寫一個循環即可,但是上下和左右的判斷邏輯可能會出現想不到的BUG,於是爲了保險起見就寫了四個,其實單單就正確率和時間上來看,寫四個其實是最有利於這次測試,但是並不利於邏輯的訓練;

因爲可能有的地方,比如十字交叉的位置,如果單單用一個二維數組可能比較難處理,所以乾脆就設置兩個二維數組,如果多次對某一位置進行消除則,效果是一樣的。

代碼

#include <iostream>

using namespace std;
int n,m;
int a[35][35];
int b[35][35];

void to_up(int i,int j){
	int x = i;
	int y = j;
	int term = a[i][j];
	int cnt = 1;
	while(1){
		x--;
		if(x<0)break;
		if(a[x][y]==term)cnt++;
		if(a[x][y]!=term)break;
	}
	if(cnt>=3){
		for(int x = i; x >= 0; x--){
			b[x][y] = 0;
			cnt--;
			if(cnt==0)break;
		}
	}
}

void to_down(int i,int j){
	int x = i;
	int y = j;
	int term = a[i][j];
	int cnt = 1;
	while(1){
		x++;
		if(x>n)break;
		if(a[x][y]==term)cnt++;
		if(a[x][y]!=term)break;
	}
	if(cnt>=3){
		for(int x = i;x < n; x++){
			b[x][y] = 0;
			cnt--;
			if(cnt==0)break;
		}
	}
}

void to_left(int i,int j){
	int x = i;
	int y = j;
	int term = a[i][j];
	int cnt = 1;
	while(1){
		y--;
		if(y<0)break;
		if(a[x][y]==term)cnt++;
		if(a[x][y]!=term)break;
	}
	if(cnt>=3){
		for(int y = j;y < 0; y--){
			b[x][y] = 0;
			cnt--;
			if(cnt==0)break;
		}
	}
}

void to_right(int i,int j){
	int x = i;
	int y = j;
	int term = a[i][j];
	int cnt = 1;
	while(1){
		y++;
		if(y>m)break;
		if(a[x][y]==term)cnt++;
		if(a[x][y]!=term)break;
	}
	if(cnt>=3){
		for(int y = j;y < m; y++){
			b[x][y] = 0;
			cnt--;
			if(cnt==0)break;
		}
	}
}

int main(){
	cin>>n>>m;
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			cin>>a[i][j];
			b[i][j]=a[i][j];
		}
	}
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			to_up(i,j);
			to_down(i,j);
			to_left(i,j);
			to_right(i,j);
		}
	}
	
	for(int i=0;i<n;i++){
		for(int j=0;j<m;j++){
			if(j==0)cout<<b[i][j];
			else cout<<" "<<b[i][j];
		}
		cout<<endl;
	}
	
	
}

T4 咕咕東學英語

咕咕東很聰明,但他最近不幸被來自宇宙的宇宙射線擊中,遭到了降智打擊,他的英語水平被歸 零了!這一切的始作俑者宇宙狗卻毫不知情! 此時咕咕東碰到了一個好心人——TT,TT在吸貓之餘教咕咕東學英語。今天TT打算教咕咕東字母A 和字母B,TT給了咕咕東一個只有大寫A、B組成的序列,讓咕咕東分辨這些字母。 但是咕咕東的其他學科水平都還在,敏銳的咕咕東想出一個問題考考TT:咕咕東問TT這個字符串 有多少個子串是Delicious的。 TT雖然會做這個問題,但是他吸完貓發現輝夜大小姐更新了,不想回答這個問題,並拋給了你, 你能幫他解決這個問題嗎?
Delicious定義:對於一個字符串,我們認爲它是Delicious的當且僅當它的每一個字符都屬於一個大於1的迴文子串中。

輸入

輸入第一行一個正整數n,表示字符串長度, 接下來一行,一個長度爲n,只由大寫字母A、B構成的字符串。

輸出

輸出僅一行,表示符合題目要求的子串的個數。

樣例輸入

5 
AABBB

樣例輸出

6

樣例解釋:

對於該樣例,符合條件的六個子串分別是:
s1-s4 AABB
s1-s5 AABBB
s3-s4 BB
s3-s5 BBB
s4-s5 BB

思路

以前做這種題都是順着推,這道題倒是給提醒了一個別具一格的思路–>求補集;

綜述

這道題剛剛開始做的時候,一門心思地想着如何去列出所有的情況,然後逐一擊破。但是沒想到的是求補集,也就是不行的情況更簡單;
滿足以下條件的就是不行的:

  • A後面跟着若干個B
  • B後面跟着若干個A
  • 若干個A後面一個B
  • 若干個B後面一個A

然後呢,求出所有子串的數量,然後減去上面提到的不滿足情況的就可以了;
在這裏插入圖片描述

注意

AB和BA可能會被計算兩次,注意減去一次

代碼

#include<iostream>
#include<vector>
#include<cstring>
#include<string.h>
#include<string>
using namespace std;

struct node{
	char ch;
	long long num;
	node(){
		num=0;
	}
};
long long n;
string s;
vector<node> v;
int main(){
	cin>>n>>s;
	char c;

	int number=0;
	for(int i=0;i<s.size();i++){
		if(i==0){
			c = s[i];
			number=1;
		}
		else if(s[i]==c){
			number++;
		}else{
			node newnode;
			newnode.ch = c;
			newnode.num = number;
			v.push_back(newnode);
			c = s[i];
			number = 1;
		}
	}
		node newnode;
		newnode.ch = c;
		newnode.num = number;
		v.push_back(newnode);	

		long long ans = (n-1)*n/2;
		if(v.size()==1)cout<<ans<<endl;
		else{
			for(int i=0;i<v.size();i++){
				if(i==0 || i==v.size()-1){
					ans-=v[i].num;
					continue;
				}
				ans-=v[i].num*2;
			}
			ans+=v.size()-1;
			cout<<ans<<endl;
		}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章