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];
}
posted @ 2020-08-05 18:09  蒟蒻丁  阅读(94)  评论(0编辑  收藏  举报