luogu2766
分析:
对于这种一个点只能选一次的问题我们拆点
然后考虑连边,就是如果dp的时候一个点可以转移到另一个点就可以连边,然后跑个最大流就完了
第三问就是把1和n的流量设成inf
Code:
#include
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
const int N=1005;
const int M=100005;
const int inf=(1<<29);
int n;
namespace DP{
int ans=0,a[N],dp[N];
inline int work(){
dp[1]=1;
for(int i=1;i<=n;i++){
int t=0;
for(int j=1;j<i;j++) if(a[j]<=a[i]) t=max(t,dp[j]);
dp[i]=t+1;
}
for(int i=1;i<=n;i++) ans=max(ans,dp[i]);
return ans;
}
}
using namespace DP;
namespace Dinic{
int tot=1,vis[M<<1],head[M<<1],nxt[M<<1],e[M<<1];
inline void add(int x,int y,int z){
vis[++tot]=y;nxt[tot]=head[x];head[x]=tot;e[tot]=z;
vis[++tot]=x;nxt[tot]=head[y];head[y]=tot;e[tot]=0;
}
queue<int>q;
int s=0,t=n*2+1,d[N];
inline bool spfa(){
memset(d,0,sizeof(d));
while(!q.empty()) q.pop();
q.push(s);d[s]=1;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=head[x];i;i=nxt[i]){
int y=vis[i];
if(!d[y] && e[i]){
q.push(y);
d[y]=d[x]+1;
if(y==t) return 1;
}
}
}
return 0;
}
int dinic(int x,int flow){
if(x==t) return flow;
int rest=flow,k;
for(int i=head[x];i && rest;i=nxt[i])
if(e[i] && d[vis[i]]==d[x]+1){
k=dinic(vis[i],min(rest,e[i]));
if(!k) d[vis[i]]=0;
e[i]-=k;e[i^1]+=k;
rest-=k;
}
return flow-rest;
}
inline int mxflow(){
int flow=0,maxflow=0;
while(spfa())
while(flow=dinic(s,inf)) maxflow+=flow;
return maxflow;
}
}
using namespace Dinic;
int main(){
n=read();
for(int i=1;i<=n;i++) a[i]=read();
int mx=work();
cout<<mx<<endl;
s=0;t=n*2+1;
for(int i=1;i<=n;i++) add(i,i+n,1);
for(int i=1;i<=n;i++) if(dp[i]==1) add(s,i,1);
for(int i=1;i<=n;i++) if(dp[i]==mx) add(i+n,t,1);
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,1);
cout<<mxflow()<<endl;tot=1;
memset(head,0,sizeof(head));
for(int i=1;i<=n;i++) add(i,i+n,(i==1||i==n?inf:1));
for(int i=1;i<=n;i++) if(dp[i]==1) add(s,i,(i==1?inf:1));
for(int i=1;i<=n;i++) if(dp[i]==mx) add(i+n,t,(i==n?inf:1));
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,1);
cout<<mxflow()<<endl;
return 0;
}