題解:CF1256D Binary String Minimizing

sapo1o發表於2024-07-06

貪心。

資料範圍 \(n \le 10^{6}\),因此我們要用時間複雜度為 \(\mathcal{O}\left( n \right)\) 的演算法來解決這個問題。

思路

從左至右掃一遍序列,如果遇到 \(10\) ,則要將這個 \(0\) 交換到前面的位置。由於是字典序最小,\(0\) 應該儘量在最高位。現在需要知道這個 \(0\) 被交換到哪個位置,因此我們有變數 \(t\) 來記錄下一個 \(0\) 所在的位置。

記剛才找到的 \(10\)\(0\) 的位置為 \(i\)。則要交換 \(i-t\) 次,我們只需要判斷 \(k\ge i-t\) 是否成立即可。

如果成立,則直接交換,將 序列的第 \(t\) 個位置置為 \(0\),第 \(i\) 個位置,置為 \(1\)。這樣成立的原因是因為序列的第 \(t\)\(i-1\) 這些位置的數不可能有 \(0\),因此我們並不需要去移動,直接 \(\mathcal{O}\left( 1 \right)\) 交換即可。

如果不成立,則儘量向前交換,將序列的第 \(i-k\) 個為位置置為 \(0\)(還能交換 \(k\) 次),第 \(i\) 個位置置為 \(1\),這樣做的正確性與上文相同。

程式碼

注意小特判:如果序列的前面一段都是 \(0\)\(t\) 的初始值應為這一段的最後一個位置 \(+1\)

long long 否則爆炸,\(n^{2}\ge 2147483647\)\(2147483647\)int 最大值。

#include <bits/stdc++.h>
using namespace std;
#define int long long
int n,k,t;
const int maxn=1e6+5;
int a[maxn];

void Main(){
	cin>>n>>k;
	for(int i=1;i<=n;i++){
		char ch;
		cin>>ch;
		a[i]=ch-'0';
	}
	int t=1,g=1;
	while(a[g]==0) t++,g++;
	for(int i=2;i<=n;i++){
		if(a[i-1]==1&&a[i]==0){
			if(k>=i-t){
				k-=i-t;
				a[t]=0,a[i]=1;
				if(k==0) break;
				t++;
			}
			else{
				a[i-k]=0,a[i]=1;
				break;
			}
		}
	}
	for(int i=1;i<=n;i++) cout<<a[i];
	cout<<"\n";
}
signed main(){
	int T;
	cin>>T;
	while(T--) Main();
	return 0;
}

相關文章