貪心。
資料範圍 \(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;
}