给定正整数序列x1,…,xn 。
(1)计算其最长不下降子序列的长度s。
(2)计算从给定的序列中最多可取出多少个长度为s的不下降子序列。
(3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长度为s的不下降子序列。
«编程任务:
设计有效算法完成(1)(2)(3)提出的计算任务。
对于这个题目,首先可以很简单的用DP求出第一个问题的答案,不过这个地方不能用nlogn的算法,因为这样不利于处理前后关系,我们采用朴素的n2 算法,记住它所转移过来的点。
对于第二个问题,运用第一次DP处理出来的关系进行连边,每个流量都是1
第三个问题同样如此,唯一不同就是首尾和ST的连边是INF
int c[N],f[N],ans=0;
int main () {
n=read();
s=n+1,t=n+2;
for (int i=1; i<=n; ++i) c[i]=read();
for (int i=1; i<=n; ++i) f[i]=1;
for (int i=1; i<=n; ++i) {
for (int j=1; j<i; ++j) {
if (c[i]>=c[j])
f[i]=max(f[i], f[j]+1);
}
if (f[i]==1) add(s,i,1);
else for (int j=1; j<i; ++j)
if (c[i]>=c[j]&&f[j]==f[i]-1)
add(j,i,1)
ans=max(ans,f[i]);
}
for (int i=1; i<= n; ++i)
if (f[i]==ans) add(i,t,1);
cout<<ans<<endl;
int in;
while (bfs ()) {while ((in=dinic (s,INF))) maxf+=in;}
cout<<maxf<<endl;
memset(head,0,sizeof(head));
memset(a,0,sizeof(a));
maxf=0;
add(s, 1, INF);
for (int i=1; i<=n; ++i) f[i] = 1;
for (int i=2; i<=n; ++i) {
for (int j=1; j<i; ++j)
if (c[i]>=c[j])
f[i]=max(f[i],f[j]+1);
if (f[i]==1) add(s,i,1);
else for (int j=1; j<i; ++j)
if (c[i]>=c[j]&&f[j]==f[i]-1)
add(j,i,1);
}
for (int i=1; i<=n-1; ++i)
if (f[i]==ans) add(i,t,1);
if (f[n]==ans) add(n,t,INF);
while (bfs ()) {while ((in=dinic (s,INF))) maxf+=in;}
cout<<maxf<<endl;
return 0;
}