把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

CF1761F1 Anti-median (Easy Version)

题面传送门

牛逼题,比赛的时候以为能自动满足\(l\leq r\)的限制然后以为条件不充分。

首先我们先来找一个充要条件,假设\(a_1<a_2\)

考虑\(n=3\)的段,容易发现这些段形成一个\(a_1<a_2>a_3\)的形状。

然后考虑\(n=5\)的段,如果\(a_3>a_1\),则\(a_5\)必定大于\(a_3\),然后归纳可以得出奇数位必定成为一条上升的链。

如果\(a_3<a_1\),则如果\(a_5>a_3\)就到第一种情况,否则归纳得出会下降。

综合一下就是奇数位单谷,仿照这样对偶数位归纳就是偶数位单峰。

显然这样是必要的,然后也可以证明是充分的:

考虑一段区间的中点,因为左右至少一边是单调的,其必定有一边完全大于它或小于它,而另一边至少有一个大于它或小于它,因此这个数一定不是中位数。

考虑怎么计算这个东西。从小到大往序列中填数,可以发现就是从\(1\)开始往两边两格一跳扩展,然后碰到边界就反弹,最后在奇偶性不同的另一边的\(0\)汇集。

\(f_{i,j}\)表示一边跳到了\(i\),另一边跳到了\(j\),并且满足\(i\leq j\)的方案数,只要看看这个数是否被确定从而判断能不能转移即可。时间复杂度\(O(n^2)\),代码中为了避免转移顺序的问题将这个序列先剖了出来。

code:

#include<bits/stdc++.h>
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((m)*(x-1)+(y))
#define R(n) (rnd()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;
using namespace std;const int N=2e3+5,M=N*4+5,K=1e5+5,mod=1e9+7,Mod=mod-1,INF=1e9+7;const db eps=1e-5;mt19937 rnd(time(0));
int n,m,k,x,y,z,A[N],H,Q[N],I1[N],I2[N],Pl[N];ll f[N][N],Ans;
void Solve(){
	int i,j,k;scanf("%d",&n);for(i=1;i<=n;i++) Pl[i]=-1;for(i=1;i<=n;i++) scanf("%d",&A[i]),Pl[A[i]]=i,I1[i]=I2[i]=0;
	H=0;x=2;while(x+2<=n) x+=2;while(x>=2) Q[I1[x]=++H]=x,x-=2;x++;
	while(x<=n) Q[I1[x]=++H]=x,x+=2;x-=2;if(x==n) x--;else x++;while(x>=1) Q[I2[x]=++H]=x,x-=2;
	for(i=1;i<=H;i++) for(j=1;j<=H;j++) f[i][j]=0;
	if(~Pl[1]) Pl[1]&1&&(f[I1[Pl[1]]][I1[Pl[1]]]=1);else for(i=1;i<=n;i+=2) f[I1[i]][I1[i]]=1;
	for(k=2;k<n;k++){
		for(i=1;i+k-1<=H;i++){
			j=i+k-1;if(Q[i]>=Q[j]) continue;if(~Pl[k]){
				if(I1[Pl[k]]==i) f[i][j]+=f[i+1][j];
				if(I1[Pl[k]]==j) f[i][j]+=f[i][j-1];
				if(I2[Pl[k]]==j) f[i][j]+=f[i][j-1];
				if(I2[Pl[k]]==i) f[i][j]+=f[i+1][j];
			}else f[i][j]=f[i+1][j]+f[i][j-1];f[i][j]%=mod;
		}
	}Ans=0;for(i=2;i+n-2<=H;i++) {j=i+n-1;
		if(~Pl[n]) {if(I1[Pl[n]]==i-1) Ans+=f[i][i+n-2];}else Ans+=f[i][i+n-2];
	}
	for(i=1;i<=n;i++) I1[i]=I2[i]=0;H=0;x=1;while(x+2<=n) x+=2;while(x>=1) Q[I1[x]=++H]=x,x-=2;x=2;
	while(x<=n) Q[I1[x]=++H]=x,x+=2;x-=2;if(x==n) x--;else x++;while(x>=1) Q[I2[x]=++H]=x,x-=2;
	for(i=1;i<=H;i++) for(j=1;j<=H;j++) f[i][j]=0;
	if(~Pl[1]) !(Pl[1]&1)&&(f[I1[Pl[1]]][I1[Pl[1]]]=1);else for(i=2;i<=n;i+=2) f[I1[i]][I1[i]]=1;
	for(k=2;k<n;k++){
		for(i=1;i+k-1<=H;i++){
			j=i+k-1;if(Q[i]>=Q[j]) continue;if(~Pl[k]){
				if(I1[Pl[k]]==i) f[i][j]+=f[i+1][j];
				if(I1[Pl[k]]==j) f[i][j]+=f[i][j-1];
				if(I2[Pl[k]]==j) f[i][j]+=f[i][j-1];
				if(I2[Pl[k]]==i) f[i][j]+=f[i+1][j];
			}else f[i][j]=f[i+1][j]+f[i][j-1];f[i][j]%=mod;
		}
	}for(i=2;i+n-2<=H;i++) {j=i+n-1;
		if(~Pl[n]) {if(I1[Pl[n]]==i-1) Ans+=f[i][i+n-2];}else Ans+=f[i][i+n-2];
	}
	printf("%lld\n",Ans%mod); 
}
int main(){
	freopen("1.in","r",stdin);
	int t;scanf("%d",&t);while(t--) Solve();
}
posted @ 2022-11-23 19:12  275307894a  阅读(47)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end