A Twisty Movement题解
这题又开阔了我的眼界
不考虑翻转这个条件,a[i]只有1和2时,就很是快乐
最长不下降子序列肯定长这样
\(11……22……\)
我们处理一下,把1和2放在两组中
\([11……][22……]\)
定义 \(f[i][j]\) (j为1或2)为前i个点,第i个点属于第j组
\[f[i][1]=f[i-1][j]+(a[i]==1)
\]
\[f[i][2]=max(f[i-1][1],f[i-1][2]+(a[i]==2))
\]
考虑一下翻转,比如
\(1112212211212222\)
它翻转后的最长不下降子序列是
\(11111122222222\)
(翻转区间 \(4、12\))
要是我们翻转回来,这个序列就变成了
\(11122221112222\)
发现它可以分为4组
\([111][2222][111][2222]\) (毕竟这样的话交换23区间就变成了上面的情况了)
所以就可以列出方程
\[f[i][1]=f[i-1][1]+(a[i]==1)
\]
\[f[i][2]=max(f[i-1][1],f[i-1][2]+(a[i]==2)
\]
\[f[i][3]=max(f[i-1][2],f[i-1][3]+(a[i]==1)
\]
\[f[i][4]=max(f[i-1][3],f[i-1][4]+(a[i]==2)
\]
然后我们压掉第一维就可
提供一个理解思路(以 \(f[i][2]\) 为例)
1.从 \(f[i-1][1]\) 转移:开启一个新的组
2.从 \(f[i-][2]\) 转移:往已经开启的组添加一个数
#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
ll n,m,f[10],ans;
int main(){
scanf("%lld",&n);
for(ll i=1;i<=n;i++){
ll a1;
scanf("%lld",&a1);
f[1]+=(a1==1);
f[2]=max(f[1],f[2]+(a1==2));
f[3]=max(f[2],f[3]+(a1==1));
f[4]=max(f[3],f[4]+(a1==2));
}
cout<<f[4];
}