題意
給定一個正整數序列x1,...,xn 。
(1)計算其最長不下降子序列的長度s。
(2)從序列中最多可不重複使用數字地取出多少個長度爲s的不下降子序列。
(3)如果允許在取出的序列中多次使用x1和xn,求解(2)
題解
第一問很經典,數據範圍一看,N^2地DP就完事兒了,做出DP數組還能幫助第二問的解答。
第二問中,每個點只能用一次,老規矩直接拆點。用DP做出以第i位開始,最長的不下降子序列長度是多少。
超級源點連上所有長度位S的點,所有長度爲i的點連上超級匯點。若DP[i]==DP[j]+1,且i<j,a[i]>=a[j],那麼i,j連邊。跑最大流即可
第三問,改下第二問中首尾兩個點的流量即可。
代碼
#include<bits/stdc++.h>
#define MAXN 1109
#define MAXM 4000000+1109
#define INF 0x3fffffff
using namespace std;
int n,m;
int a[MAXN];
int DP[MAXN];
int S,T,Long;
int dis[MAXN],dl[MAXN];
int Head[MAXN],Next[MAXM],To[MAXM],FB[MAXM],Flow[MAXM],Cnt=0;//MAXMÒª¿¼ÂÇ·´±ß
int cur[MAXN];//µ±Ç°»¡ÓÅ»¯
int Ans=0;
void ADD(int x,int y,int z)
{
Cnt++;Next[Cnt]=Head[x];Head[x]=Cnt;To[Cnt]=y;FB[Cnt]=Cnt+1,Flow[Cnt]=z;
Cnt++;Next[Cnt]=Head[y];Head[y]=Cnt;To[Cnt]=x;FB[Cnt]=Cnt-1,Flow[Cnt]=0;
}
bool BFS(int Begin,int End)
{
int t=0,w=1,x,X;
memset(dis,0xff,sizeof(dis));
dis[Begin]=0;dl[1]=Begin;
do
{
x=dl[++t];
for(int i=Head[x];i;i=Next[i])
{
X=To[i];
if(Flow[i]<=0||dis[X]>=0) continue;
dis[X]=dis[x]+1;dl[++w]=X;
}
}while(t<w);
if(dis[End]>0) return true;
else return false;
}
int Find(int x,int MFLOW,int y)
{
if(x==y) return MFLOW;
int X,h;
for(int i=cur[x];i;i=Next[i])
{
cur[x]=i;
X=To[i];
if(Flow[i]>0&&dis[x]+1==dis[X]&&(h=Find(X,min(MFLOW,Flow[i]),y)))
{
Flow[i]-=h;
Flow[FB[i]]+=h;
return h;
}
}
return 0;
}
int Solve(int x,int y)
{
int X,Liu=0;
while(1)
{
if(!BFS(x,y)) break;
for(int i=S;i<=T;i++)//³õʼ»¯È«Ìåcur
cur[i]=Head[i];
while((X=Find(x,0x7fffffff,y)))
Liu+=X;
}
return Liu;
}
int main()
{
scanf("%d",&n);
S=0;T=2*n+1;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),DP[i]=1;
for(int i=n;i;i--)
for(int j=i+1;j<=n;j++)
if(a[i]<=a[j])
DP[i]=max(DP[i],DP[j]+1);
for(int i=1;i<=n;i++)
Long=max(Long,DP[i]);
printf("%d\n",Long);
for(int i=1;i<=n;i++)
{
if(DP[i]==Long) ADD(S,i,1);
ADD(i,i+n,1);
if(DP[i]==1) ADD(i+n,T,1);
for(int j=i+1;j<=n;j++)
if(a[i]<=a[j]&&DP[i]==DP[j]+1)
ADD(i+n,j,1);
}
Ans=Solve(S,T);
printf("%d\n",Ans);
if(DP[1]==Long) ADD(S,1,INF);
ADD(1,1+n,INF);
if(DP[n]==1) ADD(n+n,T,INF);
ADD(n,n+n,INF);
Ans+=Solve(S,T);
printf("%d",Ans);
return 0;
}