CodeForces - 1370E Binary Subsequence Rotation(思維)

題目鏈接:點擊查看

題目大意:給出一個只由 0 或 1 組成的字符串 s ,和一個字符串 t ,問 s 至少需要操作多少次,才能變爲 t,每次操作是:可以選擇字符串 s 中的一個子序列,使得他們全部向右移動一個單位,如:s = 1\textbf{1}101\textbf{00},選擇的子序列爲位置\{2, 6, 7 \},經過操作後 s 就變爲了 s = 1\textbf{0}101\textbf{10}

題目分析:很顯然的兩個結論是,如果字符串 s 和字符串 t 中 1 的數量或者 0 的數量不相等,那麼輸出 -1 ,還有一點就是,如果字符串 s 和字符串 t 中的某一位置 s[ i ] == t[ i ] ,則這個位置無需操作,可以視爲被刪除就好了

接下來考慮貪心,子序列的長度肯定得大於等於 2 ,稍微舉舉例子不難發現,每次操作只能選擇偶數串的 0101... 或者 1010...,舉個反例就是,如果選擇的 s 爲 011,那麼經過操作後變爲了 101,第三個位置沒有變化,所以選不選第三個位置沒有影響,同理得出每次只能選擇偶數個的 01 交替的子序列進行操作纔是具有貢獻的

然後貪心放,就拿s = 110100t=001011爲例,此時已經將所有 s[ i ] == t[ i ] 的位置都刪除掉了,從 1 ~ n 遍歷一遍字符串,當遍歷到第一個位置時,s[ 1 ] == 1 ,所以 ans++ ,另外這裏有一個單獨的 1,到了第二個位置時,s[ 2 ] == 1,所以仍然讓 ans++,此時有兩個單獨的 1 ,到了第三個位置,此時 s[ 3 ] == 0 ,因爲前面已經有兩個單獨的 1 了,所以我們貪心讓這個 0 與第一個 1 匹配,此時 ans 不變,我們有一個 “10” 串和一個 “1” 串,到了第四個位置,此時 s[ 4 ] == 1 ,因爲此時第一個串中可以接一個 1 了,所以我們就可以直接將當前的 1 與 “10” 匹配,此時有一個 “101” 串和一個 “1” 串,剩下的兩個位置都是 0 ,我們直接讓其與兩個串匹配即可,即最後的兩次操作分爲 “1010” 和 “10” ,答案爲 2 是最優的

再看一個例子,這樣我就只給出字符串 s 了,如果s=1001,按照上面的貪心,當匹配完前三個位置後,我們得到了兩個串:“10” 和 “0” ,到了第四個串的 s[ 4 ] == 1,按理說和第一個串或者第二個串都是可以匹配的,但是我們發現如果和第一個串匹配的話,最後就無法形成偶數個 1010... 了,所以此時應該選擇其與第二個串匹配

知道原理後 O( n ) 去模擬就好了

代碼:
 

#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
using namespace std;

typedef long long LL;

typedef unsigned long long ull;

const int inf=0x3f3f3f3f;

const int N=1e6+100;

char s[N],t[N];

int main()
{
#ifndef ONLINE_JUDGE
//  freopen("input.txt","r",stdin);
//  freopen("output.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	int n;
	scanf("%d%s%s",&n,s+1,t+1);
	int sum=0,mmax=0,mmin=0;
	for(int i=1;i<=n;i++)
	{
		sum+=s[i]-t[i];
		mmax=max(mmax,sum);//記錄最多有多少個連續的“1”需要讓 ans++
		mmin=min(mmin,sum);//記錄最多有多少個連續的“0”需要讓 ans++
	}
	printf("%d\n",sum?-1:mmax-mmin);














    return 0;
}

 

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