算法:
对于第一问,设f[i]为以i这个位置为结尾的最长递增子序列的长度,一个O(n^2)的DP即可;
对于第二问,因为每个位置仅能选一次,我们可以把一个位置i拆成两个节点i1与i2,每一个i1各向对应的i2连一条无限流量的边,源点S向每一个f[i]=1的i的i1连一条流量为1的边,再由每一个f[i]=第一问答案的节点i的i2向汇点T连一条流量为1的边,最后对于每一组满足f[i]=f[j]+1且co[i]>=co[j]的i与j,由节点i2向j1连一条流量为1的边。求网络最大流即可。
对于第三问,我们在第二问的边的基础上,把S流向i1的边、i1流向i2的边、n1流向n2的边的流量都改为无限,最后如果存在n2流向T的边的话,也把该边的流量改为无限。求网络最大流即可。
(具体细节参考程序)
Code:
#include<bits/stdc++.h>
#define rep(i,j,k) for(int i=j;i<=k;i++)
using namespace std;
template<typename T> void read(T &num){
char c=getchar();num=0;T f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){num=(num<<3)+(num<<1)+(c^48);c=getchar();}
num*=f;
}
template<typename T> void qwq(T x){
if(x>9)qwq(x/10);
putchar(x%10+'0');
}
template<typename T> void write(T x){
if(x<0){x=-x;putchar('-');}
qwq(x);putchar('\n');
}
template<typename T> void chkmax(T &x,T y){x=x>y?x:y;}
int s,t;
int co[510];int f[510];
struct wzy{
int nxt,vertice,w;
}edge[300010];
int head[1010];int len=1;
inline void add_edge(int x,int y,int z){
edge[++len].nxt=head[x];edge[len].vertice=y;
edge[len].w=z;head[x]=len;return;
}
int d[1010];queue<int>v;
inline bool bfs(){
memset(d,0,sizeof(d));
while(!v.empty())v.pop();
v.push(s);d[s]=1;
while(!v.empty()){
int nop=v.front();v.pop();
for(int i=head[nop];i;i=edge[i].nxt){
int temp=edge[i].vertice;
if(edge[i].w&&!d[temp]){
v.push(temp);d[temp]=d[nop]+1;
if(temp==t)return 1;
}
}
}
return 0;
}
inline int dinic(int now,int val){
if(now==t)return val;
int k=0;
for(int i=head[now];i&&val!=k;i=edge[i].nxt){
int nop=edge[i].vertice;
if(!edge[i].w||d[nop]!=d[now]+1)continue;
int temp=dinic(nop,min(val-k,edge[i].w));
edge[i].w-=temp;edge[i^1].w+=temp;k+=temp;
}
return k;
}
int main(){
int n;read(n);
rep(i,1,n){read(co[i]);}
int ans1,ans2;ans1=ans2=0;
s=0;t=2*n+1;
if(n==1&&co[1]==1){
write(1);write(1);write(1);return 0;
}
f[1]=1;ans1=1;
rep(i,2,n){
f[i]=1;
rep(j,1,i-1){if(co[i]>=co[j]){chkmax(f[i],f[j]+1);}}
chkmax(ans1,f[i]);
}
write(ans1);
rep(i,1,n){if(f[i]==1){add_edge(s,2*i-1,1);add_edge(2*i-1,s,0);}}
rep(i,1,n){add_edge(2*i-1,2*i,1);add_edge(2*i,2*i-1,0);}
rep(i,1,n){if(f[i]==ans1){add_edge(2*i,t,1);add_edge(t,2*i,0);}}
rep(i,1,n){
rep(j,1,i-1){
if(f[i]==f[j]+1&&co[i]>=co[j]){add_edge(2*j,2*i-1,1);add_edge(2*i-1,2*j,0);}
}
}
int flow=0;
while(bfs()){
do{
flow=dinic(s,INT_MAX);ans2+=flow;
}while(flow);
}
write(ans2);
add_edge(s,1,INT_MAX);add_edge(1,2,INT_MAX);add_edge(2*n-1,2*n,INT_MAX);
if(f[n]==ans1){add_edge(2*n,t,INT_MAX);}
flow=0;
while(bfs()){
do{
flow=dinic(s,INT_MAX);ans2+=flow;
}while(flow);
}
write(ans2);
return 0;
}