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,[<,<]\) 这两种。这两种情况是对称的,考虑第一种,枚举 \([>,>]\) 前的区间个数得到:
其中最后一个分数是任意区间的方案数,对于这一部分考虑 \(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\):
转化为求最后一个 \(\Sigma\)。
请注意 \(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;
}

浙公网安备 33010602011771号