洛谷1410 子序列
题目描述
给定一个长度为N(N为偶数)的序列,问能否将其划分为两个长度为N/2的严格递增子序列,
输入输出格式
输入格式:若干行,每行表示一组数据。对于每组数据,首先输入一个整数N,表示序列的长度。之后N个整数表示这个序列。
输出格式:同输入行数。对于每组数据,如果存在一种划分,则输出“Yes!”,否则输出“No!“。
输入输出样例
输入样例#1:
6 3 1 4 5 8 7 6 3 2 1 6 5 4
输出样例#1:
Yes! No!
说明
【数据范围】
共三组数据,每组数据行数<=50,0 <= 输入的所有数 <= 10^9
第一组(30%):N <= 20
第二组(30%):N <= 100
第三组(40%):N <= 2000
我们先设f[i][j]表示前i位A有j位时,B最后一位的最小值
但这样显然有后效性,我们稍作修改:
f[i][j]表示A最后一位为a[i],有j位时,B最后一位的最小值
这样就满足最优子结构了
转移时考虑a[i+1]的大小
a[i]<a[i+1]说明a[i+1]可以放在A后面
f[i+1][j+1]=min(f[i][j])
f[i][j]<a[i+1]说明可以放在B后面
但是此刻发现不能转移了,因为转移的目标状态为f[i][j]
我们这时可以交换A和B
f[i+1][i-j+1]=min(a[i])
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int f[2001][2001],a[2001],n,inf; 7 int main() 8 {int i,j; 9 while (cin>>n) 10 { 11 for (i=1;i<=n;i++) 12 { 13 scanf("%d",&a[i]); 14 } 15 memset(f,127,sizeof(f)); 16 f[1][1]=-1; 17 inf=f[0][0]; 18 for (i=1;i<n;i++) 19 { 20 for (j=0;j<=i;j++) 21 if (f[i][j]!=inf) 22 { 23 if (a[i]<a[i+1]) 24 f[i+1][j+1]=min(f[i+1][j+1],f[i][j]); 25 if (f[i][j]<a[i+1]) 26 f[i+1][i-j+1]=min(f[i+1][i-j+1],a[i]); 27 } 28 } 29 if (f[n][n/2]==inf) 30 cout<<"No!\n"; 31 else cout<<"Yes!\n"; 32 } 33 }