P2766 最长不下降子序列问题
【题意】
【分析】
第一问直接$n^2的LIS即可
第二问我们开始用到这种套路的LIS网络流建图方式了
【代码】
#include<bits/stdc++.h> using namespace std; #define mp make_pair #define fi first #define se second #define lson now<<1 #define rson now<<1|1 typedef long long ll; const int maxn=1e3+5; const int maxm=1e6+5; int n,a[maxn],f[maxn]; int S,T; const ll inf=1e17; int head[maxn],tot=1,cur[maxn]; struct edge { int to,nxt; ll v; }e[maxm<<1]; void add(int x,int y,ll z) { e[++tot].to=y; e[tot].nxt=head[x]; e[tot].v=z; head[x]=tot; e[++tot].to=x; e[tot].nxt=head[y]; e[tot].v=0; head[y]=tot; } int dep[maxn]; bool bfs() { for(int i=S;i<=T;i++) dep[i]=-1,cur[i]=head[i]; // memset(dep,-1,sizeof(dep)); // memcpy(cur,head,sizeof(cur)); queue <int> q; dep[S]=0; q.push(S); while(!q.empty()) { int u=q.front(); q.pop(); for(int i=head[u];i;i=e[i].nxt) { int to=e[i].to; if(dep[to]!=-1 || !e[i].v) continue; q.push(to); dep[to]=dep[u]+1; } } return (dep[T]!=-1); } ll dfs(int u,ll flow) { if(u==T) return flow; ll res=0; for(int &i=cur[u];i;i=e[i].nxt) { int to=e[i].to; if(dep[to]!=dep[u]+1 || e[i].v<=0) continue; ll tmp=dfs(to,min(e[i].v,flow)); flow-=tmp; res+=tmp; e[i].v-=tmp; e[i^1].v+=tmp; if(!flow) break; } if(!res) dep[u]=-1; return res; } ll ans; ll dinic() { while(bfs()) { ans+=dfs(S,inf); } return ans; } int main() { // freopen("a.in","r",stdin); // freopen("a.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); S=0; T=n*2+1; for(int i=1;i<=n;i++) f[i]=1; int maxlen=0; for(int i=1;i<=n;i++) { for(int j=1;j<i;j++) { if(a[j]<=a[i]) f[i]=max(f[i],f[j]+1); } maxlen=max(maxlen,f[i]); } printf("%d\n",maxlen); for(int i=1;i<=n;i++) if(f[i]==1) add(S,i,1); for(int i=1;i<=n;i++) if(f[i]==maxlen) add(i+n,T,1); for(int i=1;i<=n;i++) add(i,i+n,1); for(int i=1;i<=n;i++) for(int j=1;j<i;j++) if(a[j]<=a[i] && f[i]==f[j]+1) add(j+n,i,1); printf("%d\n",dinic()); if(n==1) printf("1"); else{ add(1,n+1,inf); add(S,1,inf); if(f[n]==maxlen) add(n,n+n,inf),add(n+n,T,inf); printf("%d\n",dinic()); } return 0; }