Description
给出一个长度为n的序列,求其最长上升子序列的长度和满足最长长度的子序列的个数
Input
多组用例,每组用例第一行为一整数n表示序列长度,第二行n个整数表示该序列,以文件尾结束输入
Output
对于每组用例,第一行输出最长上升子序列长度,第二行输出不同的最长上升子序列个数
Sample Input
4
3 6 2 5
Sample Output
2
2
Solution
以dp[i]表示以i结尾的最长上升子序列长度,用朴素的O(n*2)或者优化过的O(n*logn)做法得到dp数组后,考虑将所有最长上升子序列表示在一个网络中:
两排点,因为序列中每个元素在LIS中只能出现一次,从i到i+n建流量为1的边;
dp[i]=1,从源点s到i建流量为1的边;
dp[i]=m,从i+n到汇点e建流量为1的边;
dp[j]=dp[i]+1&&j>i&&a[j]>a[i],从i+n到j建流量为1的边
那么问题就转化为在这个网络中求最大流,跑一边Dinic即可
Code
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
#define maxn 2222
#define maxm 2222222
#define INF 0x3f3f3f3f
int head[maxn],cur[maxn],d[maxn],st[maxm],s,e,no;//s为源点,e为汇点,n为点数,no为边数
int a[maxn],dp[maxn],n;//dp[i]表示最长上升子序列,n表示序列长度
int LIS(int a[])
{
for(int i=1;i<=n;i++)dp[i]=1;
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
if(a[j]>a[i])
dp[j]=max(dp[j],dp[i]+1);
int ans=0;
for(int i=1;i<=n;i++)ans=max(ans,dp[i]);
return ans;
}
struct point
{
int u,v,flow,next;
point(){};
point(int x,int y,int z,int w):u(x),v(y),next(z),flow(w){};
}p[maxm];
void add(int x,int y,int z)//从x到y建容量为z的边
{
p[no]=point(x,y,head[x],z);//前向弧,标号为偶
head[x]=no++;
p[no]=point(y,x,head[y],0);//后向弧,标号为奇
head[y]=no++;
}
void init()//初始化
{
memset(head,-1,sizeof(head));
no=0;
}
bool bfs()
{
int i,x,y;
queue<int>q;
memset(d,-1,sizeof(d));
d[s]=0;
q.push(s);
while(!q.empty())
{
x=q.front();
q.pop();
for(i=head[x];i!=-1;i=p[i].next)
{
if(p[i].flow&& d[y=p[i].v]<0)
{
d[y]=d[x]+1;
if(y==e)
return true;
q.push(y);
}
}
}
return false;
}
int dinic()//最大流
{
int i,loc,top,x=s,nowflow,maxflow=0;
while(bfs())
{
for(i=s;i<=e;i++)
cur[i]=head[i];
top=0;
while(true)
{
if(x==e)
{
nowflow=INF;
for(i=0;i<top;i++)
{
if(nowflow>p[st[i]].flow)
{
nowflow=p[st[i]].flow;
loc=i;
}
}
for(i=0;i<top;i++)
{
p[st[i]].flow-=nowflow;
p[st[i]^1].flow+=nowflow;
}
maxflow+=nowflow;
top=loc;
x=p[st[top]].u;
}
for(i=cur[x];i!=-1;i=p[i].next)
if(p[i].flow&&d[p[i].v]==d[x]+1)
break;
cur[x]=i;
if(i!=-1)
{
st[top++]=i;
x=p[i].v;
}
else
{
if(!top)
break;
d[x]=-1;
x=p[st[--top]].u;
}
}
}
return maxflow;
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
int m=LIS(a);
init();
s=0,e=2*n+1;
for(int i=1;i<=n;i++)
{
add(i,i+n,1);
if(dp[i]==1)add(s,i,1);
if(dp[i]==m)add(i+n,e,1);
for(int j=i+1;j<=n;j++)
if(dp[j]==dp[i]+1&&a[j]>a[i])
add(i+n,j,1);
}
int ans=dinic();
printf("%d\n%d\n",m,ans);
}
return 0;
}