loading

P8425 [JOI Open 2022] 长颈鹿 Giraffes

这题也太厉害了,我甘拜下风。

题意

给定一个长度为 \(n\) 的排列 \(p\),定义一个排列是好的当且仅当对于所有 \(1\le l\le r\le n\),下列条件至少一条不满足:

  • 存在 \(l<k<r\),使得 \(a_l<a_k,a_k>a_r\)
  • 存在 \(l<k<r\),使得 \(a_l>a_k,a_k<a_r\)

现在你可以对这个排列进行任意交换,求最多能使多少个数保持在原来的位置。

\(n\le 8000\),数据随机,7s。

分析

不难发现,\(1,n\) 这两个元素必定有一个会放在排列的最左或最右侧,否则取 \(l=1,r=n,k=1,n出 现的位置\) 就推翻了。同理的,在剩下的 \(n-1\) 个元素中填 \(n-1\) 个位置,剩余的元素中的最值之一也必须有一个填在这些位置的最左或最右端,这样我们就把原问题分解成了规模更小的子问题,并且由上述过程中可知,剩余的位置连续且值域也连续。据此设 \(f_{l,r,v}\) 表示将 \([v,v+r-l]\) 内的数填入 \([l,r]\) 中的最小代价。时间复杂度 \(O(n^3)\)

但这条路前途不大,因为状态数已经爆了。我们不妨将 \([l,r],[v,v+r-l]\) 看成一个矩阵(实际上是一个正方形)。而正方形的四个角就是我们要选的 \((i,p'_i)\)(这里假设 \(p'\) 是操作后的排列)。那我们的目标就是选出尽可能多的 \((i,p_i)\) 使得存在一种扩张顺序以这些点为四个角。据此设 \(f_{i,j,d=0/1/2/3}\) 表示考虑 \((i,p_i)\) 这个点,正方形边长为 \(j\)\((i,p_i)\) 是正方形的那个角的答案,虽然转移仍然是 \(O(n^3)/O(n^4)\),但状态数压到了 \(O(n^2)\)

考虑到数据随机,结合几组数据,我们大胆猜测答案不会太大!实际上答案的数量级为 \(O(\sqrt n)\),不大于 LIS+LDS 的长度,不会证感性理解即可。那么 DP 状态的值域就降到了 \(O(\sqrt n)\) 量级,考虑定义域值域交换,设 \(f_{i,j,d}\) 表示考虑 \((i,p_i)\),已经选出了 \(j\) 个点,方向是 \(d\) 的最小边长。

考虑进一步优化。以 \((i,p_i)\) 在正方形左上角为例,写出转移方程:

\[f_{i,j}=\min_{\text{condition}}f_{i',j-1}+\max(x-i,y-p_i) \]

其中 \((x,y)\) 为以 \((i'.p_{i'})\)\(d\) 方向的角的正方形的左上角坐标,\(\text{condition}\) 代表新的 \(f_{i,j}\)\(len\) 要满足 \(i+len-1\le n,p_i+len-1\le n,i<x,p_i<y\) 这些条件。

\(\max\) 拆掉,并钦定一个最大值,假设它是 \(x-i\)。我们现在的限制形如 \(p_i+len+x-i-1\le n,i<x,p_i<y,x-i\ge y-p_i\) 这些条件(注意在此情况下 \(i+len-1+x-i=x+len-1\le n\) 可以转移前提前判断),四维偏序的形式,肯定做不了。考虑减少一些不必要的条件,首先,考虑到状态是求最小边长,而边长越大 \(p_i+len+x-i-1\le n\) 的条件越不容易满足,我们不妨不要这个条件,那么若 DP 值不满足这个条件那么后续转移它一定是不合法的,只需要转移前提前判断 DP 值是否合法即可。剩下了三个条件,但是注意到 \(p_i<y\)\(x-i\ge y-p_i\) 必然能推出 \(i<x\)\(0<y-p_i\le x-i\)),所以最终剩下了两个条件,做二维偏序即可。对于其他四个角的两种最大值情况如法炮制地做八遍二维偏序即可。

时间复杂度 \(O(n\sqrt n\log n)\),常数可想而知。

点击查看代码
```plaintext
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<map>
#include<unordered_map>
#include<vector>
#include<queue>
#include<stack>
#include<bitset>
#include<set>
#include<ctime>
#include<random>
#include<cassert>
#define x1 xx1
#define y1 yy1
#define IOS ios::sync_with_stdio(false)
#define ITIE cin.tie(0)
#define OTIE cout.tie(0)
#define PY puts("Yes")
#define PN puts("No")
#define PW puts("-1")
#define P0 puts("0")
#define P__ puts("")
#define PU puts("--------------------")
#define mp make_pair
#define fi first
#define se second
#define gc getchar
#define pc putchar
#define pb emplace_back
#define un using namespace
#define il inline
#define all(x) x.begin(),x.end()
#define mem(x,y) memset(x,y,sizeof x)
#define popc __builtin_popcountll
#define rep(a,b,c) for(int a=(b);a<=(c);++a)
#define per(a,b,c) for(int a=(b);a>=(c);--a)
#define reprange(a,b,c,d) for(int a=(b);a<=(c);a+=(d))
#define perrange(a,b,c,d) for(int a=(b);a>=(c);a-=(d))
#define graph(i,j,k,l) for(int i=k[j];i;i=l[i].nxt)
#define lowbit(x) ((x)&-(x))
#define lson(x) ((x)<<1)
#define rson(x) ((x)<<1|1)
//#define double long double
//#define int long long
//#define int __int128
using namespace std;
using i64=long long;
using u64=unsigned long long;
using pii=pair<int,int>;
template<typename T1,typename T2>inline void ckmx(T1 &x,T2 y){x=x>y?x:y;}
template<typename T1,typename T2>inline void ckmn(T1 &x,T2 y){x=x<y?x:y;}
inline auto rd(){
	int qwqx=0,qwqf=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')qwqf=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){qwqx=(qwqx<<1)+(qwqx<<3)+ch-48;ch=getchar();}return qwqx*qwqf;
}
template<typename T>inline void write(T qwqx,char ch='\n'){
	if(qwqx<0){qwqx=-qwqx;putchar('-');}
	int qwqy=0;static char qwqz[40];
	while(qwqx||!qwqy){qwqz[qwqy++]=qwqx%10+48;qwqx/=10;}
	while(qwqy--)putchar(qwqz[qwqy]);if(ch)putchar(ch);
}
bool Mbg;
const int mod=998244353;
template<typename T1,typename T2>inline void adder(T1 &x,T2 y){x+=y,x=x>=mod?x-mod:x;}
template<typename T1,typename T2>inline void suber(T1 &x,T2 y){x-=y,x=x<0?x+mod:x;}
const int maxn=1e4+5,B=400,inf=0x3f3f3f3f;
const long long llinf=0x3f3f3f3f3f3f3f3f;
int n,a[maxn];
/*
0 (+,+)
1 (+,-)
2 (-,+)
3 (-,-)
*/
int f[2][maxn][2][2];
struct BIT{
	int c[maxn<<1];
	il void init(){rep(i,1,n<<1)c[i]=inf;}
	il void add(int x,int y){while(x<=(n<<1))ckmn(c[x],y),x+=lowbit(x);}
	il int qry(int x){int res=inf;while(x)ckmn(res,c[x]),x-=lowbit(x);return res;}
} T;
vector<pii>v[maxn];
vector<pii>q[maxn];
il void init(){
	T.init();
	rep(i,1,n)v[i].clear(),q[i].clear();
}
/*
以 0 0 为例:
y>a[i],x-i>y-a[i] -> x>i
同理
x>i,x-i<y-a[i] -> y>a[i]
*/
il bool ck(int x,int y,int c,int d,int len){
	!c?x+=len-1:x-=len-1;
	!d?y+=len-1:y-=len-1;
	return x>=1&&x<=n&&y>=1&&y<=n;
}
inline void solve_the_problem(){
	n=rd();
	rep(i,1,n)a[i]=rd();
	mem(f,0x3f);
	rep(i,1,n)f[1][i][0][0]=1;
	int ans=1;
	rep(j,2,B){
		const int t=j&1;
		mem(f[t],0x3f);
		//0 0
		//a[i]<y,i-a[i]<x-y
		init();
		rep(k,1,n)rep(c,0,1)rep(d,0,1){
			const int len=f[t^1][k][c][d];
			if(len==inf||!ck(k,a[k],c,d,len))continue;
			const int x=k-c*(len-1),y=a[k]-d*(len-1);
			v[y].emplace_back(mp(x-y+n,len+x));
		}
		rep(i,1,n)q[a[i]].emplace_back(mp(i-a[i]+n,i));
		per(i,n,1){
			for(pii _:q[i]){
				int r=_.fi,id=_.se;
				ckmn(f[t][id][0][0],T.qry(2*n-r)-id);
			}
			for(pii _:v[i]){
				int x=_.fi,val=_.se;
				T.add(2*n-x+1,val);
			}
		}
		//i<x,i-a[i]>=x-y
		init();
		rep(k,1,n)rep(c,0,1)rep(d,0,1){
			const int len=f[t^1][k][c][d];
			if(len==inf||!ck(k,a[k],c,d,len))continue;
			const int x=k-c*(len-1),y=a[k]-d*(len-1);
			v[x].emplace_back(mp(x-y+n,len+y));
		}
		rep(i,1,n)q[i].emplace_back(mp(i-a[i]+n,i));
		per(i,n,1){
			for(pii _:q[i]){
				int r=_.fi,id=_.se;
				ckmn(f[t][id][0][0],T.qry(r)-a[id]);
			}
			for(pii _:v[i]){
				int x=_.fi,val=_.se;
				T.add(x,val);
			}
		}
		//0 1
		//a[i]>y,a[i]+i<x+y
		init();
		rep(k,1,n)rep(c,0,1)rep(d,0,1){
			const int len=f[t^1][k][c][d];
			if(len==inf||!ck(k,a[k],c,d,len))continue;
			const int x=k-c*(len-1),y=a[k]+(d^1)*(len-1);
			v[y].pb(mp(x+y,len+x));
		}
		rep(i,1,n)q[a[i]].pb(mp(a[i]+i,i));
		rep(i,1,n){
			for(pii _:q[i]){
				int r=_.fi,id=_.se;
				ckmn(f[t][id][0][1],T.qry(2*n-r)-id);
			}
			for(pii _:v[i]){
				int x=_.fi,val=_.se;
				T.add(2*n-x+1,val);
			}
		}
		//x>i,x+y<=a[i]+i
		init();
		rep(k,1,n)rep(c,0,1)rep(d,0,1){
			const int len=f[t^1][k][c][d];
			if(len==inf||!ck(k,a[k],c,d,len))continue;
			const int x=k-c*(len-1),y=a[k]+(d^1)*(len-1);
			v[x].emplace_back(mp(x+y,len-y));
		}
		rep(i,1,n)q[i].pb(mp(i+a[i],i));
		per(i,n,1){
			for(pii _:q[i]){
				int r=_.fi,id=_.se;
				ckmn(f[t][id][0][1],T.qry(r)+a[id]);
			}
			for(pii _:v[i]){
				int x=_.fi,val=_.se;
				T.add(x,val);
			}
		}
		//1 0
		//x+y<=i+a[i],a[i]<y
		init();
		rep(k,1,n)rep(c,0,1)rep(d,0,1){
			const int len=f[t^1][k][c][d];
			if(len==inf||!ck(k,a[k],c,d,len))continue;
			const int x=k+(c^1)*(len-1),y=a[k]-d*(len-1);
			v[y].pb(mp(x+y,len-x));
		}
		rep(i,1,n)q[a[i]].pb(mp(i+a[i],i));
		per(i,n,1){
			for(pii _:q[i]){
				int r=_.fi,id=_.se;
				ckmn(f[t][id][1][0],T.qry(r)+id);
			}
			for(pii _:v[i]){
				int x=_.fi,val=_.se;
				T.add(x,val);
			}
		}
		//x+y>i+a[i],i>x
		init();
		rep(k,1,n)rep(c,0,1)rep(d,0,1){
			const int len=f[t^1][k][c][d];
			if(len==inf||!ck(k,a[k],c,d,len))continue;
			const int x=k+(c^1)*(len-1),y=a[k]-d*(len-1);
			v[x].pb(mp(x+y,len+y));
		}
		rep(i,1,n)q[i].pb(mp(i+a[i],i));
		rep(i,1,n){
			for(pii _:q[i]){
				int r=_.fi,id=_.se;
				ckmn(f[t][id][1][0],T.qry(2*n-r)-a[id]);
			}
			for(pii _:v[i]){
				int x=_.fi,val=_.se;
				T.add(2*n-x+1,val);
			}
		}
		//1 1
		//x-y<=i-a[i],y<a[i]
		init();
		rep(k,1,n)rep(c,0,1)rep(d,0,1){
			const int len=f[t^1][k][c][d];
			if(len==inf||!ck(k,a[k],c,d,len))continue;
			const int x=k+(c^1)*(len-1),y=a[k]+(d^1)*(len-1);
			v[y].pb(mp(x-y+n,len-x));
		}
		rep(i,1,n)q[a[i]].pb(mp(i-a[i]+n,i));
		rep(i,1,n){
			for(pii _:q[i]){
				int r=_.fi,id=_.se;
				ckmn(f[t][id][1][1],T.qry(r)+id);
			}
			for(pii _:v[i]){
				int x=_.fi,val=_.se;
				T.add(x,val);
			}
		}
		//x-y>i-a[i],x<i
		init();
		rep(k,1,n)rep(c,0,1)rep(d,0,1){
			const int len=f[t^1][k][c][d];
			if(len==inf||!ck(k,a[k],c,d,len))continue;
			const int x=k+(c^1)*(len-1),y=a[k]+(d^1)*(len-1);
			v[x].pb(mp(x-y+n,len-y));
		}
		rep(i,1,n)q[i].pb(mp(i-a[i]+n,i));
		rep(i,1,n){
			for(pii _:q[i]){
				int r=_.fi,id=_.se;
				ckmn(f[t][id][1][1],T.qry(2*n-r)+a[id]);
			}
			for(pii _:v[i]){
				int x=_.fi,val=_.se;
				T.add(2*n-x+1,val);
			}
		}
		rep(i,1,n)rep(c,0,1)rep(d,0,1)if(f[t][i][c][d]<=n){
			if(!ck(i,a[i],c,d,f[t][i][c][d]))continue;
			ans=j;
			goto looop;
		}
	looop:
		if(ans!=j)break;
	}
	write(n-ans);
}
bool Med;
signed main(){
//	freopen(".in","r",stdin);freopen(".out","w",stdout);
	fprintf(stderr,"%.3lfMB\n",(&Mbg-&Med)/1048576.0);
	int _=1;
	while(_--)solve_the_problem();
}
/*
96
80 30 84 26 53 63 96 48 15 40 35 10 81 68 55 57 25 2 41 56 64 65 42 74 93 69 58 32 21 85 14 79 22 38 51 8 5 27 19 20 16 94 31 23 86 36 17 77 75 62 12 87 71 76 11 13 52 44 45 4 46 60 54 3 73 70 72 66 67 92 88 59 61 7 34 89 24 49 18 37 28 91 47 1 90 9 95 82 83 33 29 78 50 6 43 39
output:73
*/
</details>
posted @ 2025-06-26 20:28  dcytrl  阅读(40)  评论(4)    收藏  举报