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

A B C D Sum Rank
50 20 60 8 138 10/21

A. 万花筒

对于一条边,假设 \(u<v\),则会连出 \(\gcd(n,v-u)\) 个环。于是按照 kruskal 的思路,每一个环留一条边不取即可。

Code
#include<bits/stdc++.h>
#define int long long
#define il inline
#define gcd __gcd
using namespace std;
namespace asbt{
const int maxn=1e5+5;
int T,n,m;
struct node{
	int u,v,w;
	node(int u=0,int v=0,int w=0):u(u),v(v),w(w){}
	il bool operator<(const node &x)const{
		return w<x.w;
	}
}e[maxn];
int main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>T;
	while(T--){
		cin>>n>>m;
		for(int i=1,u,v,w;i<=m;i++){
			cin>>u>>v>>w;
			if(u>v){
				swap(u,v);
			}
			e[i]=node(u,v,w);
		}
		sort(e+1,e+m+1);
		int ans=0;
		for(int i=1;i<=m;i++){
			int d=e[i].v-e[i].u;
			int t=gcd(n,d);
			ans+=e[i].w*(n-t);
			n=t;
		}
		cout<<ans<<"\n";
	}
	return 0;
}
}
signed main(){return asbt::main();}

B. 冒泡排序趟数期望

记每一个位置 \(i\) 前比 \(p_i\) 大的有 \(num_i\) 个,那么 \(res=\max_{i=1}^{n}num_i\)。又不难发现对于每个合法的 \(num\),都有一个唯一的 \(p\) 与之对应。于是可以枚举 \(k\),计算有多少个排列的 \(\max\{num_i\}=k\)。前 \(k\) 位可以乱选,后面的最大值一定为 \(k\),所以 \(k\) 的答案即为 \(k![(k+1)^{n-k}-k^{n-k}]\)

Code
#include<bits/stdc++.h>
#define ll long long
#define il inline
using namespace std;
namespace asbt{
const int maxn=1e6+5,mod=1e9+7;
int n,fac[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;
}
int main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n;
	fac[0]=1;
	for(int i=1;i<=n;i++){
		fac[i]=fac[i-1]*1ll*i%mod;
	}
	int ans=0;
	for(int i=0;i<n;i++){
		(ans+=i*1ll*fac[i]%mod*(qpow(i+1,n-i)-qpow(i,n-i)+mod)%mod)%=mod;
	}
	cout<<ans*1ll*qpow(fac[n])%mod;
	return 0;
}
}
int main(){return asbt::main();}

C. 数点

首先可以将点数的 \(k\) 次方拆成 \(j\le k\) 个点的贡献的线性和。具体地,对于 \(k=2\)\((a+b)^2=a^2+2ab+b^2\),于是一个点会有 \(1\) 的贡献,两个点会有 \(2\) 的贡献。\(k=3\) 是类似的。

我们分别考虑 \(j=1,2,3\) 的情况。对于 \(j=1\)\((i,p_i)\) 的贡献(即包含它的矩形数量)为 \(i\cdot p_i\cdot (n-i+1)\cdot (n-p_i+1)\)。这可以线性求出。

\(j=2\),设 \(x<y\land p_x<p_y\),贡献为 \(x\cdot p_x\cdot (n-y+1)\cdot (n-p_y+1)\)。于是可以扫描线,将 \(x\cdot p_x\) 插入树状数组,在 \(y\) 查询。对于 \(p_x>p_y\) 将数组倒过来再扫一遍即可。

\(j=3\),分布有 \(6\) 中情况,等价下来就两种:

image

枚举中间那个点正着扫一遍再倒着扫一遍,类似的用树状数组即可。

image

容易发现第一个点贡献左边界,第二个点贡献下边界。用线段树维护 \(\texttt{左}\times\texttt{下}\)。于是在第一个点,我们在 \(p_i\) 处给左加上 \(i\) 的贡献;在第二个点,我们给 \([p_i+1,n]\) 的下全都加上 \(p_i\) 的贡献;在第三个点进行区间查询即可。注意下只能从右边贡献,不能来自左侧。

Code
#include<bits/stdc++.h>
#define int long long
#define il inline
#define lid id<<1
#define rid id<<1|1
using namespace std;
namespace asbt{
const int maxn=1e5+5,mod=998244353;
int n,m,p[maxn],hp[maxn];
struct{
	int tr[maxn];
	il void init(){
		memset(tr,0,sizeof(tr));
	}
	il int lowbit(int x){
		return x&-x;
	}
	il void add(int p,int v){
		for(;p<=n;p+=lowbit(p)){
			(tr[p]+=v)%=mod;
		}
	}
	il int query(int p){
		int res=0;
		for(;p;p-=lowbit(p)){
			(res+=tr[p])%=mod;
		}
		return res;
	}
}F;
struct node{
	int a,sum;
	node(int a=0,int sum=0):a(a),sum(sum){}
	il node operator+(const node &x)const{
		return node((a+x.a)%mod,(sum+x.sum)%mod);
	}
};
struct{
	int tag[maxn<<2];
	node tr[maxn<<2];
	il void pushup(int id){
		tr[id]=tr[lid]+tr[rid];
	}
	il void pushtag(int id,int v){
		(tag[id]+=v)%=mod;
		(tr[id].sum+=tr[id].a*v)%=mod;
	}
	il void pushdown(int id){
		if(tag[id]){
			pushtag(lid,tag[id]);
			pushtag(rid,tag[id]);
			tag[id]=0;
		}
	}
	il void build(int id,int l,int r){
		tr[id]=node(),tag[id]=0;
		if(l==r){
			return ;
		}
		int mid=(l+r)>>1;
		build(lid,l,mid);
		build(rid,mid+1,r);
	}
	il void add(int id,int l,int r,int p,int v){
		if(l==r){
			(tr[id].a+=v)%=mod;
			tr[id].sum=tag[id]=0;
			return ;
		}
		pushdown(id);
		int mid=(l+r)>>1;
		if(p<=mid){
			add(lid,l,mid,p,v);
		}
		else{
			add(rid,mid+1,r,p,v);
		}
		pushup(id);
	}
	il void mul(int id,int L,int R,int l,int r,int v){
		if(l>r){
			return ;
		}
		if(L>=l&&R<=r){
			pushtag(id,v);
			return ;
		}
		pushdown(id);
		int mid=(L+R)>>1;
		if(l<=mid){
			mul(lid,L,mid,l,r,v);
		}
		if(r>mid){
			mul(rid,mid+1,R,l,r,v);
		}
		pushup(id);
	}
	il int query(int id,int L,int R,int l,int r){
		if(L>=l&&R<=r){
			return tr[id].sum;
		}
		pushdown(id);
		int mid=(L+R)>>1,res=0;
		if(l<=mid){
			(res+=query(lid,L,mid,l,r))%=mod;
		}
		if(r>mid){
			(res+=query(rid,mid+1,R,l,r))%=mod;
		}
		return res;
	}
}S;
il int calc1(){
	int res=0;
	for(int i=1;i<=n;i++){
		(res+=i*p[i]*(n-i+1)%mod*(n-p[i]+1))%=mod;
	}
	return res;
}
il int calc2(){
	int res=0;
	F.init();
	for(int i=1;i<=n;i++){
		(res+=(n-i+1)*(n-p[i]+1)%mod*F.query(p[i]))%=mod;
		F.add(p[i],i*p[i]%mod);
	}
	reverse(p+1,p+n+1);
	F.init();
	for(int i=1;i<=n;i++){
		(res+=(n-i+1)*(n-p[i]+1)%mod*F.query(p[i]))%=mod;
		F.add(p[i],i*p[i]%mod);
	}
	return res;
}
il int calc3(){
	int res=0;
	F.init();
	for(int i=1;i<=n;i++){
		hp[i]=F.query(p[i]);
		F.add(p[i],i*p[i]%mod);
	}
	F.init();
	for(int i=n;i;i--){
		(res+=hp[i]*(F.query(n)-F.query(p[i])+mod))%=mod;
		F.add(p[i],(n-i+1)*(n-p[i]+1)%mod);
	}
	reverse(p+1,p+n+1);
	F.init();
	for(int i=1;i<=n;i++){
		hp[i]=F.query(p[i]);
		F.add(p[i],i*p[i]%mod);
	}
	F.init();
	for(int i=n;i;i--){
		(res+=hp[i]*(F.query(n)-F.query(p[i])+mod))%=mod;
		F.add(p[i],(n-i+1)*(n-p[i]+1)%mod);
	}
	S.build(1,1,n);
	for(int i=1;i<=n;i++){
		(res+=(n-i+1)*(n-p[i]+1)%mod*S.query(1,1,n,1,p[i]))%=mod;
		S.add(1,1,n,p[i],i);
		S.mul(1,1,n,p[i]+1,n,p[i]);
	}
	reverse(p+1,p+n+1);
	S.build(1,1,n);
	for(int i=1;i<=n;i++){
		(res+=(n-i+1)*(n-p[i]+1)%mod*S.query(1,1,n,1,p[i]))%=mod;
		S.add(1,1,n,p[i],i);
		S.mul(1,1,n,p[i]+1,n,p[i]);
	}
	for(int i=1;i<=n;i++){
		p[i]=n-p[i]+1;
	}
	S.build(1,1,n);
	for(int i=1;i<=n;i++){
		(res+=(n-i+1)*(n-p[i]+1)%mod*S.query(1,1,n,1,p[i]))%=mod;
		S.add(1,1,n,p[i],i);
		S.mul(1,1,n,p[i]+1,n,p[i]);
	}
	reverse(p+1,p+n+1);
	S.build(1,1,n);
	for(int i=1;i<=n;i++){
		(res+=(n-i+1)*(n-p[i]+1)%mod*S.query(1,1,n,1,p[i]))%=mod;
		S.add(1,1,n,p[i],i);
		S.mul(1,1,n,p[i]+1,n,p[i]);
	}
	return res;
}
int main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>p[i];
	}
	int ans=0;
	switch(m){
		case 1:{
			ans=calc1();
			break;
		}
		case 2:{
			ans=(calc1()+2*calc2())%mod;
			break;
		}
		default:{
			ans=(calc1()+6*calc2()+6*calc3())%mod;
			break;
		}
	}
	cout<<ans;
	return 0;
}
}
signed main(){return asbt::main();}

D. 精shen细腻

posted @ 2025-07-11 21:17  zhangxy__hp  阅读(41)  评论(1)    收藏  举报