标签:Binary String int Kirk version LIS 长度 dp 子列
hard version 的 On 做法我老早就看题解弄懂了,但 easy version 的 n2 暴力直到现在才想明白。。。
题意:
给定一个01串,尽量把1改成0,要求任意子区间的 LIS 长度保持不变。
这里的 LIS 为最长不降子列
串长2000
思路:
若把某个1改成0之后,以它为左端点的所有子区间的 LIS 长度保持不变,那就可以改。解释:
对某个固定的 \(L\),把 \(s_L\) 从1改成0后 \(\forall R\in[L,n],\text{LIS}(L,R)\) 的长度不变 \(\iff \text{LIS}(L,R)\) 都是以1而非0开头 \(\iff\) 在 \([L,R]\) 中存在一个全1子列(11111),其长度严格大于任一 0011子列(修改 \(s_L\) 后,0011的长度最多和原来的11111相等)
考虑 \([p,R],p<L\) 的 \(\text{LIS}\) ,它的前半部分一定是区间 \([p,L-1]\) 的某个子列,后半部分要么是 \([L,R]\) 中的最长0011子列,要么是 \([L,R]\) 中的最长全1子列。由上段讨论,后半部分的长度不变,所以 \([p,R],p<L\) 的 \(\text{LIS}\) 长度也不变。
const signed N = 2003;
int n, f[N], g[N]; char s[N];
void LIS(int l, int *a) { //以l开头的所有子区间的LIS长度
static int dp[2]; dp[0] = dp[1] = 0; //以0/1结尾的LIS长度
for(int i = l; i <= n; i++) {
if(s[i] == '0') dp[0]++;
else dp[1] = max(dp[0], dp[1]) + 1;
a[i] = max(dp[0], dp[1]);
}
}
signed main() {
iofast;
cin >> s + 1; n = strlen(s + 1);
for(int i = 1; i <= n; i++)
if(s[i] == '1') {
LIS(i, f);
s[i] = '0'; LIS(i, g);
for(int j = i; j <= n; j++) //比较
if(f[j] != g[j]) s[i] = '1';
}
cout << s + 1;
}
标签:Binary,String,int,Kirk,version,LIS,长度,dp,子列 来源: https://www.cnblogs.com/wushansinger/p/16069625.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。