Luogu-CF933A
题目分析
这题乍一看不好想,但是看到 \(1 \leq a_i \leq 2\) 时,便发现有玄机。
可得知最终答案是在 \([1,1,1,...][2,2,2,...][1,1,1,...][2,2,2,...]\) 这样的序列中,通过翻转第 \(2\),\(3\) 个序列之后得出。
我们可以用动态规划来维护每一段的最大值。
定义 \(f[i][j]\) 为前 \(i\) 个数中前 \(j\) 段的答案。
对于序列
\(111112222\)
可以将其按上面分成两组。
合理运用一下判等,
则有
\[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))
\]
对于序列
\(12212211212\)
得到最终答案时的最长不下降子序列是:
\(111122222\)
在此基础上翻转回去,则为:
\(122221112\)
发现它符合上面的按 \(4\) 个组的分组形式。
则有
\[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)
\]
观察,发现状态转移方程可以压掉第一维。
核心代码
ll n,ans,f[12];
int main()
{
n=read();
for (ll i = 1; i <= n; i++)
{
ll tmp;
scanf("%lld", &tmp);
f[1] += (tmp == 1);
f[2] = max(f[1], f[2] + (tmp == 2));
f[3] = max(f[2], f[3] + (tmp == 1));
f[4] = max(f[3], f[4] + (tmp == 2));
}
printf("%lld\n",f[4]);
return 0;
}