题目描述 Description
给定正整数序列x1,..... , xn 。
(1)计算其最长递增子序列的长度s。
(2)计算从给定的序列中最多可取出多少个长度为s的递增子序列。
(3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长
度为s的递增子序列。
输入描述 Input Description
第1 行有1个正整数n,表示给定序列的长度。接
下来的1 行有n个正整数x1.....xn 。
输出描述 Output Description
第1 行是最长递增子序列的长度s。第2行是可取出的长度为s 的递增子序列个数。第3行是允许在取出的序列中多次使用x1和xn时可取出的长度为s 的递增子序列个数。
样例输入 Sample Input
4
3 6 2 5
样例输出 Sample Output
2
2
3
不得不吐槽codevs上面网络流24题好多数据都是很蛋疼的要输出方案又不给spj……鬼知道你数据是用哪种方案啊
啊这题还算正常
第一问LIS随便求
第二问拆点完S向所有x1连流量1费用0的边,所有x2向T连流量1费用0的边,所有x1向x2连流量1费用1的边。因为要表示有没有取这个点
对于所有a[i]<a[j]且i<j的,i2向j1连流量1费用0的边
然后跑最大费用。每次增广搞完如果答案是第一问的最长长度,那么ans++。
第三问就是第二问的建图与1和n有关的边的流量全改inf就对了
#include<cstdio> #include<iostream> #include<cstring> #define LL long long #define inf 0x3ffffff #define S 0 #define T 1001 using namespace std; inline LL read() { LL x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int n,ans,flow,cnt,tot; int a[510]; int mn[510]; struct edge{int from,to,next,v,c;}e[500010]; int head[1010],dis[1010],q[1010],from[1010]; bool mrk[1010]; inline void ins(int u,int v,int w,int c) { e[++cnt].to=v; e[cnt].v=w; e[cnt].c=c; e[cnt].from=u; e[cnt].next=head[u]; head[u]=cnt; } inline void insert(int u,int v,int w,int c) { ins(u,v,w,c); ins(v,u,0,-c); } inline int bsearch(int x) { int l=1,r=ans,s=0; while(l<=r) { int mid=(l+r)>>1l; if (mn[mid]<=x){s=mid;l=mid+1;} else r=mid-1; } return s; } inline bool spfa() { for (int i=1;i<=T;i++)dis[i]=inf; memset(mrk,0,sizeof(mrk)); int t=0,w=1; dis[S]=0;q[0]=S;mrk[S]=1; while (t!=w) { int now=q[t++];if (t==1005)t=0; for (int i=head[now];i;i=e[i].next) if (e[i].v&&dis[now]+e[i].c<dis[e[i].to]) { dis[e[i].to]=dis[now]+e[i].c; from[e[i].to]=i; if (!mrk[e[i].to]) { mrk[e[i].to]=1; q[w++]=e[i].to; if (w==1005)w=0; } } mrk[now]=0; } if (dis[T]==inf)return 0; return 1; } inline void mcf() { int x=inf;flow=0; for (int i=from[T];i;i=from[e[i].from]) x=min(x,e[i].v); for (int i=from[T];i;i=from[e[i].from]) { e[i].v-=x; e[i^1].v+=x; flow+=x*e[i].c; } if (flow==-ans)tot++; } int main() { n=read(); for (int i=1;i<=n;i++)a[i]=read(); ans=1;mn[1]=a[1]; for (int i=2;i<=n;i++) { int fnd=bsearch(a[i]); if (fnd==ans)mn[++ans]=a[i]; else mn[fnd+1]=a[i]; } printf("%d ",ans); cnt=1; for(int i=1;i<=n;i++) { insert(S,i,1,0); insert(i+n,T,1,0); insert(i,i+n,1,-1); } for (int i=1;i<=n;i++) for (int j=i+1;j<=n;j++) if (a[i]<=a[j])insert(i+n,j,1,0); while (spfa())mcf(); printf("%d ",tot); memset(head,0,sizeof(head)); cnt=1;tot=0; insert(S,1,inf,0);insert(S,n,inf,0); insert(1+n,T,inf,0);insert(2*n,T,inf,0); insert(1,1+n,inf,-1);insert(n,2*n,inf,-1); for(int i=1;i<=n;i++) { insert(S,i,1,0); insert(i+n,T,1,0); insert(i,i+n,1,-1); } for (int i=1;i<n;i++) for (int j=i+1;j<=n;j++) if (a[i]<=a[j]) if (i!=1&&j!=n)insert(i+n,j,1,0); else insert(i+n,j,inf,0); while (spfa())mcf(); printf("%d ",tot); }