20260604模拟赛

20260604模拟赛

闺泣

题面:

对于一个 \(0\sim 2n+1\) 的排列 \(a[0:2n]\),称之为好的当且仅当 \(\forall 0\leq i<n,a_{2i+1}<a_{2i+2}\)

对于一个好排列 \(a\),定义 \(f(a)\) 为执行以下操作后 \(x\) 的结果:

  • 初始化一个变量 \(x=a_0\)
  • 对于 \(i=1\sim n\),顺次执行 \(x=\max(x,a_{2i-1}),x=\min(x,a_{2i})\)

对于每个 \(i=0\sim 2n\),求出 \(f(a)=i\)\(a\) 的个数。 \(n\leq 10^7\)

题解:

操作的意思是让你选一个数和 \(n\) 个区间。

对于一个如果询问你 \(m\)(\(m\not= n\)),用 \(<\) 表示 \(<m\) 的数,\(=\)\(>\) 也是同理,我们只关注数和 \(m\) 的大小关系分类即可,数本身的值并不重要。那么区间从后往前的构成就是 \([<,>],\cdots,[<,>],[<,=],[<,>],\cdots,[<,>],[>,>]\) 后面是任意区间,或者是改成 \(\cdots,[=,>],\cdots,[<,<]\) 这两种。这两种情况是对称的,考虑第一种,枚举 \([>,>]\) 前的区间个数得到:

\[f_m=\sum_{i=1}^{n-1} iP(m,i)P(2n-m,i+1)\dfrac{(2n-2i-1)!}{2^{n-i}} \]

其中最后一个分数是任意区间的方案数,对于这一部分考虑 \(2n+1\) 个元素的任意区间方案数,将他们任意排列是 \((2n+1)!\),然后对于每两个数将他们按照大小关系形成一个区间,他们是否交换位置不影响最终方案,最后一个数是初值,所以方案数是 \(\dfrac{(2n+1)!}{2^n}\)

假设求出了 \(f_m\),那么询问 \(m\) 的答案是 \(f_m+f_{2n-m}\)。特别的,对于询问 \(n\) 的时候,还会多出三种情况 \([<,>],\cdots,[<,>],[n]\) 这一种,\([<,>],\cdots,[<,>],[<,=],[<,>],\cdots,[<,>],[>n]\) 以及它的对称情况。所以如果询问是 \(n\),答案是 \(2f_n+(2n+1)(n!)^2\)

现在考虑怎么求 \(f_m\)

\[f_m=\dfrac{m!(2n-m)!}{2^n}\sum_{i=1}^{n-1}\binom{2n-2i-1}{m-i}2^ii \]

转化为求最后一个 \(\Sigma\)

\[f(x)=\sum_{i=1}^{n-1}\binom{2n-2i-1}{m-i}2^ii\\ g(x)=\sum_{i=1}^{n-1}\binom{2n-2i-1}{m-i}2^i \]

请注意 \(f(x),g(x)\) 多出一项组合数变成 \(i=1\sim n\) 答案不变,因为此时组合数必然为 \(0\)

已知 \(\binom n k=\binom {n-1} k+\binom{n-1}{k-1}\),嵌套两层的到 \(\binom{n+2}{k}=\binom n k+2\binom{n}{k-1}+\binom n {k-2}\)

\(C(i,x)=\binom{2n-2i-1}{x-i}\),则有 \(C(i,x)+2C(i,x-1)+C(i,x-2)=C(i-1,x-1)\)

可得 \(f(x)+2f(x-1)+f(x-2)=\sum_{i=1}^{n}C(i-1,x-1)2^ii=\sum_{i=0}^{n-1}C(i,x-1)2^{i+1}(i+1)\)

我们企图用 \(f(x)\) 来表示它,这个式子等于 \(2\sum_{i=0}^{n-1}C(i,x-1)2^ii+2\sum_{i=0}^{n-1}C(i,x-1)2^i=2f(x-1)+2g(x-1)\)

至此得到递推式 1\(f(x)+2f(x-1)+f(x-2)=2f(x-1)+2g(x-1)\)\(f(x)+f(x-2)=2g(x-1)\)

\(g(x)\) 同样组合数嵌套两遍可以得到 \(g(x)+2g(x-1)+g(x-2)=2g(x-1)+\binom{2n+1}{x}\)

得到递推式 2\(g(x)+g(x-2)=\binom{2n+1}x\)

至此已经可以求出所有 \(f(x),g(x)\),对于边界可以暴力求前几项。求出 \(f(0\sim n)\) 之后显然可见 \(f(x)=f(2n-x)\),至此求得所有 \(f(x)\)

代码
#include<bits/stdc++.h>
#define ll long long
#define fir first
#define sec second
using namespace std;

inline int read(){
	int s=0,k=1;
	char c=getchar();
	while(c>'9'||c<'0'){
		if(c=='-') k=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9'){
		s=(s<<3)+(s<<1)+(c^48);
		c=getchar();
	}
	return s*k;
}

const int N=1e7+5,mod=998244353;
int n,Q;
ll fac[N<<1],inv[N<<1],pw[N<<1],f[N<<1];

ll ksm(ll a,ll b){
	ll t=1;
	for(;b;b>>=1,a=a*a%mod)
		if(b&1) t=t*a%mod;
	return t;
}

ll Mod(ll x){return x>=mod?x-mod:x;}
void Add(ll &x,ll y){x=Mod(x+y);}

ll C(int n,int m){
	if(n<m||n<0||m<0) return 0;
	return fac[n]*inv[m]%mod*inv[n-m]%mod;
}

int main(){
//	freopen("cry.in","r",stdin);
//	freopen("cry.out","w",stdout);
	n=read();Q=read();
	fac[0]=1;
	for(int i=1;i<=n*2+1;i++) fac[i]=fac[i-1]*i%mod;
	inv[2*n+1]=ksm(fac[n*2+1],mod-2);
	for(int i=n*2;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod;
	pw[0]=1;
	for(int i=1;i<=n*2;i++) pw[i]=Mod(pw[i-1]<<1);
	for(int x=0;x<=4;x++){
		int A=x,B=2*n-x,id=min(A-1,B-1);
		for(int i=1;i<=id+1;i++)
			(f[x]+=C(2*n-2*i-1,A-i)*pw[i]%mod*i)%=mod;
	}
	for(int x=5;x<n;x++) f[x]=Mod((2*C(2*n+1,x-1)-2*f[x-2]-f[x-4])%mod+mod);
	f[n]=f[n-1];
	for(int x=n+1;x<2*n-1;x++) f[x]=f[2*n-1-x];
	for(int x=2*n-1;x<=2*n+1;x++) f[x]=0;
	ll inc=ksm(pw[n],mod-2);
	for(int x=0;x<=n*2+1;x++) (f[x]*=fac[x]*fac[2*n-x]%mod*inc%mod)%=mod;
	while(Q--){
		int x=read();
		printf("%lld ",Mod(Mod(f[x]+f[2*n-x])+(x==n?fac[n]*fac[n]%mod*(2*n+1)%mod:0)));
	}
	return 0;
}

posted @ 2026-06-05 16:00  programmingysx  阅读(11)  评论(0)    收藏  举报
Title