题意
这个DP状态有点神。
首先考虑一个最暴力的状态:(f_{i,j,k,u})表示第一个选了(i)个,第二个选了(j)个,第一个结尾为(k),第二个结尾为(u)是否可行。
现在考虑消减状态:
1.首先知道了处理到第几个,那么只要知道一个长度就能推出另一个。 因此状态可以改为(f_{i,j,k,u})表示处理到了第(i)个,第一个序列选了(j)个,第一个序列结尾为(k),第二个序列结尾为(u)是否可行。(这并没有减少维数,只是转化下,方便处理。)
2.既然所有的数都要选,假设当前处理到了第(i)个,那么第(i-1)个必定在结尾,因此我们可以消去一维:
(f_{i,j,k})表示处理到第(i)个,结尾是(a_i)的那个序列长度为(j),另一个结尾为(k)是否可行。
3.贪心地想,一个序列结尾越小越容易接数,因此可以将一维放到DP的值中:
(f_{i,j})表示处理到第(i)个,结尾是(a_{i-1})的那个序列长度为(j),另一个结尾最小是多少。
现在我们已经将DP减到二维,于是就可以转移了:
(a_i>a_{i-1}):此时(a_i)可以拼接在(a_{i-1})后面:
(f_{i,j}=min(f_{i,j}f_{i-1,j-1}))。
(a_i>f_{i-1,i-j}):此时我们可以将(a_i)接到另一个序列后面,于是我们交换两个序列,因为另一个序列后面接了(a_i),我们要符合定义,于是可得:
(f_{i,j}=min(f_{i,j},a_{i-1}))。
最后判断(f_{n,n/2})是否为(inf)。
数据范围不知道,到某dark上看了看,(nleqslant2000)。
code:
#include<bits/stdc++.h>
using namespace std;
const int maxn=2010;
int T,n;
int a[maxn];
int f[maxn][maxn];
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
memset(f,0x3f,sizeof(f));
f[0][0]=-1;
for(int i=1;i<=n;i++)
for(int j=1;j<=min(n/2,i);j++)
{
if(a[i]>a[i-1])f[i][j]=min(f[i][j],f[i-1][j-1]);
if(a[i]>f[i-1][i-j])f[i][j]=min(f[i][j],a[i-1]);
}
puts(f[n][n/2]<0x3f3f3f3f?"Yes!":"No!");
}
return 0;
}