[cf1761F]Anti-median

  • 考虑长度为\(3\)的区间,即\(\forall i\in [2,n),a_{i}<a_{i-1},a_{i+1}\)\(a_{i}>a_{i-1},a_{i+1}\)

    不妨假设\(a_{1}<a_{2}\),则其余部分即形如\(a_{1}<a_{2}>a_{3}<...a_{n}\)

  • 考虑长度为\(5\)的区间,即\(\forall i\in [3,n-2],\begin{cases}a_{i}<a_{i-2}或a_{i}<a_{i+2} & 2\not\mid i\\a_{i}>a_{i-2}或a_{i}>a_{i+2}&2\mid i\end{cases}\)

    对于子序列\(\{a_{1},a_{3},...,a_{n/n-1}\}\),其中不存在"极大值",即在最小值两侧单调递增

    类似的,子序列\(\{a_{2},a_{4},...,a_{n/n-1}\}\)在最大值两侧单调递减

事实上,上述条件已经充分必要——

考虑任意长度的区间\([l,r]\),记假设区间中点\(k\)

不妨假设\(2\not\mid k\)\(k\)\(\{a_{1},a_{3},...,a_{n/n-1}\}\)中最小值的左侧

结合前者性质,有\(\forall i\in [l,k)\cup \{k+1\},a_{i}>a_{k}\),即\(a_{k}\)不为中位数

将序列重排为\(\{b_{n}\}=\{a_{1},a_{3},...,a_{n/n-1},a_{n-1/n},a_{n-3/n-2},...,a_{2}\}\),并将首尾相接

\(b_{i}=1,b_{j}=n\),则将\(\{b_{n}\}\)\(j\)\(j+1\)中间断开后,其在\(i\)两侧单调递增

枚举\(i\le \lceil\frac{n}{2}\rceil\),即向左右共拓展\(n-2\)次,且任意时刻区间\([l,r]\)满足\(\begin{cases}l+r\le n+1&l\le r\\l+r>n+1&l>r\end{cases}\)

  • 关于限制,当拓展到该位置时,当前的区间仅有两种,分别记录方案数即可

  • 关于两个区间之间的转移,左右拓展次数均确定,而限制即任意时刻\(左-右\in [x,y]\)

    另外,两个限制不会同时不满足,并用经典做法减掉对应方案数即可

    具体的,设左右拓展次数为\(l,r\),则答案为\(\begin{cases}0&l-r\not\in [x,y]\\{l+r\choose l}-{l+r\choose x-1+r}-{l+r\choose y+1+r}&l-r\in [x,y]\end{cases}\)

初始状态枚举\(i\)计算,最终状态枚举\(j\)求和,但当不存在限制时两者会同时枚举

此时,答案即\(\sum_{i=1}^{\lceil\frac{n}{2}\rceil}\sum_{r=\lceil\frac{n}{2}\rceil-i}^{n-i-1}{n-2\choose r}-{n-2\choose 2i-n-2+r}-{n-2\choose 2i-1+r}\),预处理\({n-2\choose m}\)的前缀和即可

时间复杂度为\(O(n)\)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1000005,mod=1000000007;
int t,n,m,ans,a[N],fac[N],inv[N],pos[N];
int l1[N],r1[N],l2[N],r2[N],f1[N],f2[N],sum[N];
int add(int x,int y){
	x+=y;
	return (x<mod ? x : x-mod);
}
int C(int n,int m){
	if ((m<0)||(m>n))return 0;
	return (ll)fac[n]*inv[m]%mod*inv[n-m]%mod;
}
int get_sum(int l,int r){
	l=max(l,0),r=min(r,n-2);
	if (l>r)return 0;
	return add(sum[r],(l ? mod-sum[l-1] : 0));
}
bool check(int l,int r){
	if (l<=r)return l+r<=n+1;
	return l+r>n+1;
}
int calc(int l,int r,int x,int y){
	return add(add(C(l+r,l),mod-C(l+r,x-1+r)),mod-C(l+r,y+1+r));
}
int move(int l1,int r1,int l2,int r2){
	int l=(l1-l2+n)%n,r=(r2-r1+n)%n;
	if ((l+r>=n)||(!check(l2,r2)))return 0;
	if (l1<=r1)return calc(l,r,l1+r1-n-1,l1+r1-2);
	return calc(l,r,-n,l1+r1-n-2);
}
int work(){
	m=0;
	for(int i=1;i<=n;i++)pos[i]=0;
	for(int i=1;i<=n;i++)
		if (a[i]>0)pos[a[i]]=((i&1) ? (i+1>>1) : n-(i>>1)+1);
	for(int i=1;i<=n;i++)
		if (pos[i]){
			if (i==1)m++,l1[m]=r1[m]=l2[m]=r2[m]=pos[i],f1[m]=1,f2[m]=0;
			else{
				l1[++m]=pos[i]%n+1,r1[m]=(pos[i]+i-2)%n+1;
				l2[m]=(pos[i]+n-i)%n+1,r2[m]=(pos[i]+n-2)%n+1;
				f1[m]=f2[m]=0;
				if (m==1){
					for(int j=1;j<=(n+1>>1);j++){
						f1[m]=add(f1[m],move(j,j,l1[m],r1[m]));
						f2[m]=add(f2[m],move(j,j,l2[m],r2[m]));
					}
				}
				else{
					f1[m]=(ll)f1[m-1]*move(l1[m-1],r1[m-1],l1[m],r1[m])%mod;
					f1[m]=(f1[m]+(ll)f2[m-1]*move(l2[m-1],r2[m-1],l1[m],r1[m]))%mod;
					f2[m]=(ll)f1[m-1]*move(l1[m-1],r1[m-1],l2[m],r2[m])%mod;
					f2[m]=(f2[m]+(ll)f2[m-1]*move(l2[m-1],r2[m-1],l2[m],r2[m]))%mod;
				}
				l1[m]=r2[m]=pos[i];
			}
			if (i<n){
				if (!check(l1[m],r1[m]))f1[m]=0;
				if (!check(l2[m],r2[m]))f2[m]=0;
			}
		}
	if (pos[n])return f1[m];
	if (m){
		int ans=0;
		for(int i=(n+1>>1)+1;i<=n;i++){
			ans=(ans+(ll)f1[m]*move(l1[m],r1[m],i%n+1,(i+n-2)%n+1))%mod;
			ans=(ans+(ll)f2[m]*move(l2[m],r2[m],i%n+1,(i+n-2)%n+1))%mod;
		}
		return ans;
	}
	int ans=0;sum[0]=1;
	for(int i=1;i<=n-2;i++)sum[i]=add(sum[i-1],C(n-2,i));
	for(int i=1;i<=(n+1>>1);i++){
		ans=add(ans,get_sum((n+1>>1)-i,n-i-1));
		ans=add(ans,mod-get_sum(i-(n>>1)-2,i-3));
		ans=add(ans,mod-get_sum(i+(n+1>>1)-1,i+n-2));
	}
	return ans;
}
int main(){
	fac[0]=inv[0]=inv[1]=1;
	for(int i=1;i<N;i++)fac[i]=(ll)fac[i-1]*i%mod;
	for(int i=2;i<N;i++)inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod;
	for(int i=1;i<N;i++)inv[i]=(ll)inv[i-1]*inv[i]%mod;
	scanf("%d",&t);
	while (t--){
		scanf("%d",&n);
		for(int i=1;i<=n;i++)scanf("%d",&a[i]);
		ans=work();
		for(int i=1;i<=n;i++)
			if (a[i]>0)a[i]=n-a[i]+1;
		printf("%d\n",add(ans,work()));
	}
	return 0;
} 
posted @ 2023-03-05 22:38  PYWBKTDA  阅读(97)  评论(0编辑  收藏  举报