問題の説明
問題の解決策
\(\ mathrm {サブタスク1} \)
問題は、最大の減少シーケンスを求めていないされた\(N- \ル500 \) 、直接\(O(N ^ 2) \) DPへの暴力。
\(\ mathrm {サブタスク2} \)
セット\(opt_i \)区間の代表\([1、I] \) 、とする(Iは\)\最長シーケンスの終わりが低減されません。
スプリットポイントを考えてみましょう、\は(私は\)に分割された\(私は\)と\(N-I + \) 。
場合\(1 opt_i = \)は、ソース・ノードからする\(Iは\)接続されたエッジを。
もし\(N-opt_i = \) 、から\(I + N \)もエッジをシンクします。
2である右の上コラージュ\(INF \) 。
次から(私は\)\する(I + N \)\接続される側、右側\(1 \)を、それぞれの数を表すことは一度だけ使用することができます。
次の列挙\(I、J \) 、および\(Iは、Jを\ <)、\ (\ FORALL a_j \ルa_iを\)と\(1 + opt_i opt_j = \)で\(J + N、I \)側との間に接続され、右側である)\(1 \。
実行\(\ mathrm {Dinic} \ ) することができます。
\(\ mathrm {サブタスク3} \)
のみを持ち上げる必要がある\(1 \)をし、\(N \)交通規制することができます。
\(\ mathrm {コード} \)
#include<bits/stdc++.h>
using namespace std;
template <typename Tp>
void read(Tp &x){
x=0;char ch=1;int fh;
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-'){
fh=-1;ch=getchar();
}
else fh=1;
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+ch-'0';
ch=getchar();
}
x*=fh;
}
const int maxn=507;
int n,a[maxn],len=1;
int opt[maxn],ans;
int S,T;
int Head[20000],v[200000],w[200000],tot=1;
int d[20000],Next[200000];
bool bfs(){
memset(d,0,sizeof(d));
queue<int>q;q.push(S);d[S]=1;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=Head[x];i;i=Next[i]){
if(d[v[i]]||!w[i]) continue;
q.push(v[i]);d[v[i]]=d[x]+1;
if(v[i]==T) return true;
}
}
return false;
}
int dfs(int x,int flow){
if(x==T) return flow;
int rest=flow;
for(int i=Head[x];i&&rest;i=Next[i]){
if(d[v[i]]!=d[x]+1||!w[i]) continue;
int k=dfs(v[i],min(rest,w[i]));
if(!k) d[v[i]]=0;
else{
w[i]-=k,w[i xor 1]+=k;
rest-=k;
}
}
return flow-rest;
}
void add(int x,int y,int z){v[++tot]=y,Next[tot]=Head[x],Head[x]=tot,w[tot]=z;}
int main(){
read(n);
for(int i=1;i<=n;i++){
read(a[i]);opt[i]=1;
}
for(int i=1;i<=n;i++){
for(int j=1;j<i;j++){
if(a[i]>=a[j]){
opt[i]=max(opt[i],opt[j]+1);
len=max(opt[i],len);
}
}
}
printf("%d\n",len);S=n*2+1,T=S+1;
for(int i=1;i<=n;i++){
if(opt[i]==1) add(S,i,1),add(i,S,0);
}
for(int i=1;i<=n;i++){
if(opt[i]==len) add(i+n,T,1),add(T,i+n,0);
}
for(int i=1;i<=n;i++) add(i,i+n,1),add(i+n,i,0);
for(int i=1;i<=n;i++){
for(int j=1;j<i;j++){
if(a[i]>=a[j]&&opt[i]==opt[j]+1){
add(j+n,i,1);add(i,j+n,0);
}
}
}
while(bfs()){
int t;
while(t=dfs(S,0x3f3f3f3f)) ans+=t;
}
printf("%d\n",ans);
add(1,1+n,0x3f3f3f3f);add(n+1,1,0);
add(S,1,0x3f3f3f3f);add(1,S,0);
if(opt[n]==len) add(n,n+n,0x3f3f3f3f),add(2*n,n,0),add(n*2,T,0x3f3f3f3f),add(T,n*2,0);
while(bfs()){
ans+=dfs(S,0x3f3f3f3f);
}
printf("%d\n",ans);
return 0;
}