Sequence
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2186 Accepted Submission(s): 789
Problem Description
There is a sequence X (i.e. x[1], x[2], ..., x[n]). We define increasing subsequence of X
as x[i1], x[i2],...,x[ik], which satisfies follow conditions:
1) x[i1] < x[i2],...,<x[ik];
2) 1<=i1 < i2,...,<ik<=n
As an excellent program designer, you must know how to find the maximum length of the
increasing sequense, which is defined as s. Now, the next question is how many increasing
subsequence with s-length can you find out from the sequence X.
For example, in one case, if s = 3, and you can find out 2 such subsequence A and B from X.
1) A = a1, a2, a3. B = b1, b2, b3.
2) Each ai or bj(i,j = 1,2,3) can only be chose once at most.
Now, the question is:
1) Find the maximum length of increasing subsequence of X(i.e. s).
2) Find the number of increasing subsequence with s-length under conditions described (i.e. num).
Input
The input file have many cases. Each case will give a integer number n.The next line will
have n numbers.
Output
The output have two line. The first line is s and second line is num.
Sample Input
4
3 6 2 5
Sample Output
2
2
Source
2011 Multi-University Training Contest 16 - Host by TJU
题目大意:
给你一个长度为n的序列,求其最长上升子序列的个数maxn,然后如果每一个数字只能用一次的条件下,能够组成几个长度为maxn的上升子序列。
思路:
1、根据Discuss中的提示,N并不会很大,(Discuss中说是2000左右),那么我们可以N^2求最长上升子序列。并且维护maxn。
设定dp【i】表示序列进行到第i个位子,并且以a【i】结尾的最长上升子序列的个数。
那么dp【i】=max(dp【i】,dp【j】+1)(a【i】>a【j】);初始化dp【i】=1;
2、然后我们能够得到一个dp【】数组,那么我们建图方式如下:
①首先每个数字只能用一次,那么我们将这个数字拆成两个点,i,i+n,并且建立从i->i+n一条边,设定流为1,表示这个点只能用一次。
②建立源点,将源点连入各个dp【i】==1的点,设定流为INF。
③建立汇点,将各个dp【i】==maxn的点连入汇点,设定流为INF。
④将所有满足:dp【i】==dp【j】+1&&a【i】>a【j】的i,j点对加入网络中,建立从j+n->i的一条边,设定流为INF。
3、建好图之后跑最大流,得到的最大流的值就是能够组成的序列的个数,那么我们输出maxn,maxflow即可。
Ac代码:
#include<stdio.h>
#include<string.h>
#include<queue>
#include<iostream>
using namespace std;
struct node
{
int from;
int to;
int w;
int next;
}e[3000500];
int cur[100060];
int divv[100060];
int head[100060];
int a[100060];
int dp[100060];
int n,cont,ss,tt,maxn;
void add(int from,int to,int w)
{
e[cont].to=to;
e[cont].w=w;
e[cont].next=head[from];
head[from]=cont++;
}
void LIS()
{
memset(dp,0,sizeof(dp));
dp[1]=1;
for(int i=2;i<=n;i++)
{
dp[i]=1;
for(int j=1;j<i;j++)
{
if(a[i]>a[j])
{
dp[i]=max(dp[i],dp[j]+1);
}
}
maxn=max(maxn,dp[i]);
}
}
void getmap()
{
cont=0;
memset(head,-1,sizeof(head));
ss=2*n+1;
tt=ss+1;
for(int i=1;i<=n;i++)
{
add(i,i+n,1);
add(i+n,i,0);
if(dp[i]==1)
{
add(ss,i,0x3f3f3f3f);
add(i,ss,0);
}
if(dp[i]==maxn)
{
add(i+n,tt,0x3f3f3f3f);
add(tt,i+n,0);
}
}
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
if(dp[j]==dp[i]+1&&a[j]>a[i])
{
add(i+n,j,0x3f3f3f3f);
add(j,i+n,0);
}
}
}
}
int makedivv()
{
queue<int >s;
s.push(ss);
memset(divv,0,sizeof(divv));
divv[ss]=1;
while(!s.empty())
{
int u=s.front();
if(u==tt)return 1;
s.pop();
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
int w=e[i].w;
if(w&&divv[v]==0)
{
divv[v]=divv[u]+1;
s.push(v);
}
}
}
return 0;
}
int Dfs(int u,int maxflow,int tt)
{
if(u==tt)return maxflow;
int ret=0;
for(int &i=cur[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
int w=e[i].w;
if(w&&divv[v]==divv[u]+1)
{
int f=Dfs(v,min(maxflow-ret,w),tt);
e[i].w-=f;
e[i^1].w+=f;
ret+=f;
if(ret==maxflow)return ret;
}
}
return ret;
}
void Dinic()
{
int ans=0;
while(makedivv()==1)
{
memcpy(cur,head,sizeof(head));
ans+=Dfs(ss,0x3f3f3f3f,tt);
}
printf("%d\n",maxn);
printf("%d\n",ans);
}
int main()
{
while(~scanf("%d",&n))
{
memset(a,0,sizeof(a));
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
maxn=0;
LIS();
getmap();
Dinic();
}
}