题意:给你一个由 1 2 构成的串 你可以倒置任意l r的一个区间 问你倒置之后的最长不下降子序列是多长
思路:这题真是曲折,想了很久想不出思路,问cygg,看懂了cygg的n2的dp代码
又自己莽了个n3的代码 982ms勉强过了
然后借鉴cygg的dp优化 几十ms 也过了
然后问px px说他没用dp就n2枚举过了 自己很震惊 啊凭什么都是枚举pxgg就n2
然后仔细询问加对比,终于找到两个人思维所在差异
pxgg用一种更巧妙的方法更深入的认识了这个问题
因为要找最终目标序列就是 11111222221111112222这样一种形式,所以只要枚举中点(中间的2和1分界点),然后枚举左边1与2分界点 右边1与2分界点即可
巧妙之处在于:枚举中点k后 左边12和右边12中点可以同时枚举,减少了一层循环
其实在于:每一个k只枚举一次!而不是像枚举区间再枚举k一样 同一个k可能枚举很多次!
。
而自己的方法是 n2枚举倒置区间,再在区间里枚举222111分界的中点。比n3少一点。
刚刚想明白:自己的方法和pxgg的方法的差距在于:
pxgg的枚举21中点 只从左往右扫了一次,而自己的,随着枚举区间的不同,会反复枚举中间的21分界点k 导致多了将近一层循环!
下面是第一次的n3莽过算法
//省略头文件 该代码 982ms 0 memory 哭辽
const int maxn=2010;
int a[maxn];
int s1[maxn],s2[maxn];//从头开始1的数量和2的数量
int main() {
int n;
sd(n);
rep(i,1,n) sd(a[i]);
rep(i,1,n){
s1[i]=s1[i-1]+(a[i]==1);
s2[i]=s2[i-1]+(a[i]==2);
}
int ans=1;
rep(i,0,n){//正常的不交换
if(ans<s1[i]+s2[n]-s2[i])
ans=s1[i]+s2[n]-s2[i];
}
rep(i,1,n-1){
rep(j,i+1,n){//交换的区间为i j
int x=s1[i-1]+s2[n]-s2[j];//两边部分
int y=0;
rep(k,i-1,j){
if(y<s2[k]-s2[i-1]+s1[j]-s1[k]){
y=s2[k]-s2[i-1]+s1[j]-s1[k];
}
}
if(ans<x+y) ans=x+y;
}
}
printf("%d\n",ans);
return 0;
}
下面是加上cygg的dp优化的n2 用空间换时间
//省略头文件 41ms左右! Memory 15m
const int maxn=2010;
int a[maxn];
int s1[maxn],s2[maxn];//从头开始1的数量和2的数量
int dp[maxn][maxn];
int main() {
int n;
sd(n);
rep(i,1,n) sd(a[i]);
rep(i,1,n){
s1[i]=s1[i-1]+(a[i]==1);
s2[i]=s2[i-1]+(a[i]==2);
}
int ans=1;
rep(i,0,n){//正常的不交换
if(ans<s1[i]+s2[n]-s2[i])
ans=s1[i]+s2[n]-s2[i];
}
//预处理一个前2后1的
cl(dp,0);
rep(i,1,n){
if(a[i]==2){
rep(j,i+1,n){
if(a[j]==1){//若当前这个是1 就看是原来所有2 还是已有的21最多
dp[i][j]=1+max(s2[j]-s2[i-1],dp[i][j-1]);
}else{
dp[i][j]=dp[i][j-1];
}
}
}
}
rep(i,1,n-1){
rep(j,i+1,n){//交换的区间为i j
ans=max(ans,s1[i-1]+dp[i][j]+s2[n]-s2[j]);
}
}
printf("%d\n",ans);
return 0;
}
下面是pxgg不用dp的大法!
枚举222111中点 再枚举左右111222中点
//31ms tql!!!
const int maxn=2010;
int a[maxn];
int s1[maxn],s2[maxn];//从头开始1的数量和2的数量
int main() {
int n;
sd(n);
rep(i,1,n) sd(a[i]);
rep(i,1,n){
s1[i]=s1[i-1]+(a[i]==1);
s2[i]=s2[i-1]+(a[i]==2);
}
int ans=1;
rep(k,0,n){//k是第一段结束的2
int tp1=0;
rep(i,0,k){//1111222211112222 i是第一个结束的1
tp1=max(tp1,s1[i]+s2[k]-s2[i]);
}
int tp2=0;
rep(j,k,n){//j是第第二段结束的1
tp2=max(tp2,s1[j]-s1[k]+s2[n]-s2[j]);
}
ans=max(ans,tp1+tp2);
}
printf("%d\n",ans);
return 0;
}