D. Kirk and a Binary String
題意
給出一個01
串S
,長度
請你構建一個01
串P
,長度與S
相同
使得對於任意l,r
,
對於區間[l,r]
的最長不下降子串長度相同
思路
- 由於只有
1
變爲0
,若[l,r]
改變,[1,n]
必定改變- 我們可以將
S
分成若干的01
串,且每個串前面都爲0
,後面都爲1
- 比如將
0111001101
分成0111
,0011
,01
[1,n]
的LIS
即爲將每個段中取出0
或1
[L,R]
的LIS
求法與[1,n]
同,若[L,R]
改變,則必定有01
分串改變
- 我們可以將
- 取上面的逆否命題,若
[1,n]
不變,[l,r]
不變
對於區間[l,r]
,若將位置i
的1
改爲0
新的最長不下降子序列長度爲:
設LIS(l,r)
爲l
到r
的最長不下降子序列,sum[x][l,r]
爲l
到r
中x
的個數
-
若
[l,i]
均爲0
,顯然可以改變爲0
,無影響 -
前面的
LIS
加上後面的1
或者後面的LIS
加上前面的0
-
顯然改變後,只改變了
0,1
個數,LIS[l][r]
不改變
代碼
預處理LIS
int cnt = 0;
for (int i = 1; i <= n; pre_dp[i] = cnt, i++) {
if (d[cnt] <= res[i]) d[++cnt] = res[i];
else d[upper_bound(d + 1, d + 1 + cnt, res[i]) - d] = res[i];
}
cnt = 0;
d[cnt] = 2;
for (int i = n; i >= 1; suf_dp[i] = cnt, i--) {
if (d[cnt] >= res[i]) d[++cnt] = res[i];
else d[upper_bound(d + 1, d + 1 + cnt, res[i],greater<int>()) - d] = res[i];
}
solve
int pre_zero = 0, suf_one = 0;
for (int i = 2; i <= n; suf_one += res[i] == 1, i++);
int lis = pre_dp[n];
for (int i = 1; i <= n; i++) {
if (res[i] && lis == max(pre_dp[i - 1] + suf_one,
pre_zero + 1 + suf_dp[i + 1])) {
res[i] = 0;
pre_zero++;
suf_one--;
} else {
pre_zero += res[i] == 0;
suf_one -= res[i] == 1;
}
}
AC
char s[maxn];
int res[maxn];
int pre_dp[maxn], suf_dp[maxn];
int d[maxn];
int main() {
scanf("%s", s + 1);
int n = strlen(s + 1);
for (int i = 1; i <= n; i++) if (s[i] == '1')res[i] = 1;
int cnt = 0;
for (int i = 1; i <= n; pre_dp[i] = cnt, i++) {
if (d[cnt] <= res[i]) d[++cnt] = res[i];
else d[upper_bound(d + 1, d + 1 + cnt, res[i]) - d] = res[i];
}
cnt = 0; d[cnt] = 2;
for (int i = n; i >= 1; suf_dp[i] = cnt, i--) {
if (d[cnt] >= res[i]) d[++cnt] = res[i];
else d[upper_bound(d + 1, d + 1 + cnt, res[i],greater<int>()) - d] = res[i];
}
int pre_zero = 0, suf_one = 0; for (int i = 2; i <= n; suf_one += res[i] == 1, i++);
int lis = pre_dp[n];
for (int i = 1; i <= n; i++) {
if (res[i] && lis == max(pre_dp[i - 1] + suf_one,
pre_zero + 1 + suf_dp[i + 1])) {
res[i] = 0; pre_zero++; suf_one--;
}
else {
pre_zero += res[i] == 0;
suf_one -= res[i] == 1;
}
}
for (int i = 1; i <= n; i++) s[i] = res[i] + '0';
printf("%s\n", s + 1);
}