2019牛客暑期多校訓練營(第三場)----B-Crazy Binary String

首先發出題目鏈接:
鏈接:https://ac.nowcoder.com/acm/contest/883/B
來源:牛客網
涉及:思維,前綴和

點擊這裏回到2019牛客暑期多校訓練營解題—目錄貼


題目如下
在這裏插入圖片描述
在這裏插入圖片描述
一道比較簡單 的思維題

此題讓我們找到原字符串中‘0’和‘1’數量相同的子串和子序列。

注意子串在原字符串是連續的;而子序列在原字符串是可以不連續的,但是順序不能改變


先討論最長的‘0’‘1’數量相同的子序列:
這個很簡單,數一數原字符串‘0’和‘1’的數量,假設‘0’的數量爲sum0sum0,‘1’的數量爲sum1sum1

那麼滿足條件的子序列最長的長度爲
2min(sum0,sum1)2*min(sum0,sum1)


再討論最長的‘0’‘1’數量相同的子串:
此時有一種方法:將原字符串的‘0’改爲‘-1’,然後求原字符串的前綴和。
在這裏插入圖片描述
由於一個‘1’會和另外一個‘-1’抵消爲0,故前綴和中如果存在兩個相同的數,說明就存在一個‘0’‘1’相同的子串:
在這裏插入圖片描述
解釋:
0與0之間最長隔了2個單位(紅色)
-1與-1之間最長隔了4個單位(綠色)
-2與-2之間最長隔了4個單位(藍色)
所以最長滿足條件子串爲max(2,4,4)=4max(2,4,4)=4

通過上面的方法,可以給前綴和每一個數標上它的位置,然後以主鍵爲前綴和數值,次主鍵爲每個數的位置進行從小到大排序,求得每兩個相同的數最長隔的單位長度,其中距離最大的單位長度就是答案。具體可以看代碼


例子上面舉了


代碼如下:

#include <iostream>
#include <algorithm>
using namespace std;

int n, word;//n爲題目所給變量,word循環存字符串每一個值
struct Num {//前綴和結構體
	int sum;//前綴和的值
	int place;//這個值的位置
};
Num num[100005];//前綴和結構體數組
int sum1 = 0, sum0 = 0;//sum1爲'1'的數量,sum0爲'0'的數量
int ans1, ans2 = 0;//ans1爲最長子序列長度的一半,ans2位最長子串長度

bool comp(Num a, Num b) {//以sum爲主鍵,place爲次主鍵
	if(a.sum == b.sum)	return a.place < b.place;
	else return a.sum < b.sum;
}

int main() {
	scanf("%d", &n);
	num[0].sum = num[0].place = 0;//先將num[0]和num[n+1]初始化
	num[n+1].sum = 100001;
	for(int i = 1; i <= n; i++) {
		scanf("%1d", &word);//循環輸入每一個字符
		if(word == 1) {
			num[i].sum = (i - 1 == 0? 0: num[i-1].sum) + 1;//更新前綴和數組
			sum1++;//記錄字符'1'個數
		}
		else{
			num[i].sum = (i - 1 == 0? 0: num[i-1].sum) - 1;//更新前綴和數組
			sum0++;//記錄字符'0'個數
		}
		num[i].place = i;//記錄每個值的位置
	}
	ans1 = min(sum1, sum0);//最長子序列長度的一半
	sort(num, num + n + 1, comp); //按照上述方法排序
	int flag = 0; //記錄每一串前綴和數相同的第一個數的位置
	for(int i = 1; i <= n; i++) {
		if(num[i].sum != num[i-1].sum) {//記錄相同數開始位置
			flag = i;
		}
		else if(num[i].sum != num[i+1].sum) {//遍歷到相同數最後一個位置
			ans2 = max(ans2, num[i].place - num[flag].place);//更新答案
		}
	}
	printf("%d %d", ans2, ans1*2);
	return 0;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章