【比赛记录】2025CSP-S模拟赛59

A B C D Sum Rank
- - 11 0 11 21/25

A. 一个赢家

显然总方案数为 \(\frac{(2n)!}{2^n}\),考虑求出合法方案数。

又显然最大值 \(i\in[2n+1,4n-1]\)。又又显然 \(i\) 的组成方式为 \(x=\lceil\frac{4n-i}{2}\rceil\)。考虑钦定一个组成 \(a+b(a>b)\),于是对于另一种组合 \(a'+b'\),要求实际给出的组合 \(a'+c\) 满足 \(c<b'\)。从大到小考虑每个 \(a'\),发现每个 \(c\) 的取值都为 \(i-2n-1\)。于是最大值为 \(i\) 的方案数即为:

\[\frac{nx{n-1\choose x-1}(x-1)!(i-2n-1)^{x-1}[2(n-x)]!}{2^{n-x}} \]

时间复杂度 \(O(n\log n)\)。轻微卡常,卡卡即可。

Code
#include<bits/stdc++.h>
#define ll long long
#define il inline
using namespace std;
namespace asbt{
const int maxn=1e7+5,mod=1e9+7;
il int qpow(int x,int y=mod-2){
	int res=1;
	while(y){
		if(y&1){
			res=res*1ll*x%mod;
		}
		x=x*1ll*x%mod,y>>=1;
	}
	return res;
}
int n,fac[maxn],inv[maxn],_2[maxn];
int main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n;
	if(n==1){
		cout<<1;
		return 0;
	}
	fac[0]=1;
	for(int i=1;i<=n<<1;i++){
		fac[i]=fac[i-1]*1ll*i%mod;
	}
	inv[n<<1]=qpow(fac[n<<1]);
	for(int i=n<<1;i;i--){
		inv[i-1]=inv[i]*1ll*i%mod;
	}
	_2[0]=1;
	for(int i=1;i<=n;i++){
		_2[i]=_2[i-1]*500000004ll%mod;
	}
	int ans=0;
	for(int i=2*n+1;i<n<<2;i++){
		int x=(4*n-i+1)>>1;
		ans=(x*1ll*n%mod*fac[n-1]%mod*inv[n-x]%mod*qpow(i-2*n-1,x-1)%mod*fac[(n-x)<<1]%mod*_2[n-x]+ans)%mod;
	}
	cout<<ans*1ll*qpow(2,n)%mod*inv[n<<1]%mod;
	return 0;
}
}
int main(){return asbt::main();}

B. 磁铁

考虑对于磁铁的一个排列 \(p\),求出使磁铁顺次摆放能占据的最小的空间 \(f(p)\),于是会对答案造成 \({l-f(p)+n\choose n}\) 的贡献。考虑求出 \(g(x)\) 表示 \(f(p)=x\)\(p\) 的数量。

发现对于两个磁铁 \(r_i\)\(r_j\),影响距离的是 \(\max(r_i,r_j)\),于是将 \(r\) 排序后进行连续段 DP。设 \(dp_{i,j,k}\) 表示前 \(i\) 个磁铁形成了 \(j\) 段,占据的总空间为 \(k\) 的方案数,于是又转移:

\[dp_{i,j,k}\times(j+1)\to dp_{i+1,j+1,k+1}\\ dp_{i,j,k}\times2\times j\to dp_{i+1,j,k+r_{i+1}}\\ dp_{i,j,k}\times(j-1)\to dp_{i+1,j-1,k+2r_{i+1}-1} \]

于是 \(g(x)=dp_{n,1,x}\)。时间复杂度 \(O(n^2l)\)

Code
#include<bits/stdc++.h>
#define ll long long
#define il inline
using namespace std;
namespace asbt{
const int maxn=3e4+5,mod=1e9+7;
int n,m,a[55],fac[maxn],inv[maxn];
int f[55][55][maxn];
il int qpow(int x,int y=mod-2){
	int res=1;
	while(y){
		if(y&1){
			res=res*1ll*x%mod;
		}
		x=x*1ll*x%mod,y>>=1;
	}
	return res;
}
il void init(){
	fac[0]=1;
	for(int i=1;i<=m;i++){
		fac[i]=fac[i-1]*1ll*i%mod;
	}
	inv[m]=qpow(fac[m]);
	for(int i=m;i;i--){
		inv[i-1]=inv[i]*1ll*i%mod;
	}
}
il int C(int x,int y){
	if(x<y||y<0){
		return 0;
	}
	return fac[x]*1ll*inv[y]%mod*inv[x-y]%mod;
}
int main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	sort(a+1,a+n+1);
	init();
	f[0][0][0]=1;
	for(int i=0;i<n;i++){
		for(int j=0;j<=i;j++){
			for(int k=0;k<=m;k++){
				f[i+1][j][k+a[i+1]]=(f[i][j][k]*2ll*j+f[i+1][j][k+a[i+1]])%mod;
				f[i+1][j+1][k+1]=(f[i][j][k]*1ll*(j+1)+f[i+1][j+1][k+1])%mod;
				if(j){
					f[i+1][j-1][k+2*a[i+1]-1]=(f[i][j][k]*1ll*(j-1)+f[i+1][j-1][k+2*a[i+1]-1])%mod;
				}
			}
		}
	}
	int ans=0;
	for(int i=0;i<=m;i++){
		ans=(C(m-i+n,n)*1ll*f[n][1][i]+ans)%mod;
	}
	cout<<ans;
	return 0;
}
}
int main(){return asbt::main();}

C. 树上染黑

定义 \(f(u,A)\) 表示 \(u\)\(A\) 的虚树的距离。

\[\begin{aligned} \operatorname{ans}_{u} & =(n-1)(n-1)!+\sum_{\left\{a_{i}\right\}} \sum_{i=1}^{n-1}(n-i) f\left(a_{i},\left\{a_{0}, \ldots, a_{i-1}\right\}\right) \\ & =(n-1)(n-1)!+\sum_{v \neq u} \sum_{i=1}^{n-1}(n-i) \sum_{|A|=i, u \in A} f(v, A)(i-1)!(n-1-i)! \\ & =(n-1)(n-1)!+\sum_{v \neq u} \sum_{i=1}^{n-1}(n-i)!(i-1)!\sum_{|A|=i, u \in A} \sum_{w \in \operatorname{anc}_{v}}[\operatorname{Subtree}(w) \cap A=\varnothing] \\ & =(n-1)(n-1)!+\sum_{v \neq u} \sum_{i=1}^{n-1}(n-i)!(i-1)!\sum_{w \in \operatorname{anc}_{v}}\binom{n-1-\operatorname{siz}_{w}}{i-1} \\ & =(n-1)(n-1)!+\sum_{w \neq u} \sum_{i=1}^{n-1}(n-i)!(i-1)!\binom{n-1-\operatorname{siz}_{w}}{i-1} \operatorname{siz}_{w} \end{aligned} \]

考虑预处理出 \(g_m=\sum_{i=1}^{n-1}(n-i)!(i-1)!{n-1-m\choose i-1}m\),于是可以换根求解。

\[\begin{aligned} g_m&=\sum_{i=1}^{n-1}(n-i)!(i-1)!{n-1-m\choose i-1}m\\ &=m(n-m-1)!\sum_{i=1}^{n-1}\frac{(n-i)!}{(n-m-i)!}\\ &=m(n-m-1)!m!\sum_{i=1}^{n-1}{n-i\choose m}\\ &=m(n-m-1)!m!{n\choose m+1}\\ &=\frac{m}{m+1}n! \end{aligned} \]

时间复杂度线性对数。

Code
#include<bits/stdc++.h>
#define ll long long
#define il inline
#define pb push_back
using namespace std;
namespace asbt{
const int maxn=1e6+5,mod=998244353;
il int pls(int x,int y){
	return x+y<mod?x+y:x+y-mod;
}
il void add(int &x,int y){
	x=pls(x,y);
}
il int mns(int x,int y){
	return x<y?x-y+mod:x-y;
}
il void sub(int &x,int y){
	x=mns(x,y);
}
int n,fac[maxn],g[maxn],ans,sz[maxn],sum[maxn];
vector<int> e[maxn];
il int qpow(int x,int y=mod-2){
	int res=1;
	while(y){
		if(y&1){
			res=res*1ll*x%mod;
		}
		x=x*1ll*x%mod,y>>=1;
	}
	return res;
}
il void dfs1(int u,int fa){
	sz[u]=1;
	for(int v:e[u]){
		if(v==fa){
			continue;
		}
		dfs1(v,u);
		add(ans,g[sz[v]]);
		sz[u]+=sz[v];
	}
}
il void dfs2(int u,int fa){
	for(int v:e[u]){
		if(v==fa){
			continue;
		}
		add(ans,g[sz[1]-sz[v]]);
		sub(ans,g[sz[v]]);
		sum[v]=((n-1)*1ll*fac[n-1]+ans)%mod;
		dfs2(v,u);
		add(ans,g[sz[v]]);
		sub(ans,g[sz[1]-sz[v]]);
	}
}
int main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n;
	for(int i=1,u,v;i<n;i++){
		cin>>u>>v;
		e[u].pb(v),e[v].pb(u);
	}
	fac[0]=1;
	for(int i=1;i<=n;i++){
		fac[i]=fac[i-1]*1ll*i%mod;
	}
	for(int i=1;i<n;i++){
		g[i]=i*1ll*fac[n]%mod*qpow(i+1)%mod;
	}
	dfs1(1,0);
	sum[1]=((n-1)*1ll*fac[n-1]+ans)%mod;
	dfs2(1,0);
	for(int i=1;i<=n;i++){
		cout<<sum[i]<<'\n';
	}
	return 0;
}
}
int main(){return asbt::main();}

D. 摆放花盆

posted @ 2025-10-05 19:27  zhangxy__hp  阅读(18)  评论(0)    收藏  举报