CSP模拟<反思> 1

7.20#

打了一天模拟赛,垫底了。

#

考场上想到了期望dp,拿到了30,但其实 op1op2 还可拿20
一看题解 原根 懵逼,但可用倍增优化dp,将 m 二进制拆分
为什么呢?
假如一个长为 l()的串相乘且,则可以分为两个相同长度的串,总串的余数为两个串的余数相乘取模。
这里采用边倍增边更新

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
const int N=1e5+10;
int mgml(int x,int p,int mm){
	int ans=1;
	while(p){
		if(p&1) ans=(ans*x)%mm;
		x=(x*x)%mm;
		p>>=1;
	}
	return ans;
}
int f[5][1005];
int g[5][1005];
int sum[N];
int n,m,mo;
signed main(){
    cin>>n>>m>>mo;
    int tmp=m;
    int z;
	for(int i=1;i<=n;i++){
    	int x;
    	scanf("%lld",&x);z=x;
    	g[0][x]++;
	}
	int of=0,og=0;
	f[of][1]=1;
	while(m){
		if(m&1){
			memset(f[of^1],0,sizeof(f[of^1]));
			for(int j=1;j<=mo;j++){
				for(int k=1;k<=mo;k++){
					int s=(k*j)%mo;
			    	f[of^1][s]+=(f[of][j]*g[og][k]%mod);
			    	f[of^1][s]%=mod;	
				}
			}
			of^=1;
		}
		memset(g[og^1],0,sizeof(g[og^1]));
		for(int j=1;j<=mo;j++){
			for(int k=1;k<=mo;k++){
				int s=(k*j)%mo;
				g[og^1][s]+=(g[og][j]*g[og][k]%mod);
				g[og^1][s]%=mod;
			}
		}
		og^=1;
		m>>=1;
	}
//	for(int i=0;i<m;i++){//原方程
//		memset(f[op^1],0,sizeof(f[op^1]));
//		for(int j=1;j<mo;j++){//枚举 余数 
//			if(f[op][j]){
//			    for(int k=1;k<mo;k++){
//			    	if(sum[k]==0) continue;
//			    	int s=(k*j)%mo;
//			    	f[op^1][s]+=f[op][j]*sum[k];
//			    	f[op^1][s]%=mod;
//				} 
//			}
//		}
//		op^=1;
//	}
	int sum=0;
	for(int i=1;i<mo;i++){
		sum+=f[of][i]*i;
		sum%=mod;
	}
	int fm=mgml(n,tmp,mod);
	cout<<sum*mgml(fm,mod-2,mod)%mod;
}
/*
2 2 3
1 2
*/

#

这道是整场考试最可做的了,考场打的高斯消元和暴力,结果写挂了。
对于 b 数组,考虑换根dp(其实是模板)设 size 表示当前节点子树的 a 之和,然后求出根节点 b ,从根节点往下推就行了。式子为
b[y]=b[x]+size[1]2size[y]

对于 a 数组,还是一样的,将上面的式子转化的到 size[y]=(b[x]b[y])/2+size[1]/2 a[y]=size[y]iysize[i]

b[1]=1<=i<=na[i]len[i]

可以求解size[1] 进而求解 a[i].

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
int head[N*2],nex[N*2],ver[N*2],tot=0;
int size[N];
int f[N];
int a[N],b[N];
int d[N]; 
int sum[N],k[N];
int summ[N],kk[N];
void add(int x,int y){
	ver[++tot]=y,nex[tot]=head[x],head[x]=tot;
	ver[++tot]=x,nex[tot]=head[y],head[y]=tot;
}
void dfs1(int x,int d,int fa){
	size[x]=a[x];
	for(int i=head[x];i;i=nex[i]){
		int y=ver[i];
		if(y==fa) continue;
		dfs1(y,d+1,x);
		size[x]+=size[y];
		f[x]+=f[y]+size[y];
	}
}
void dfs2(int x,int fa){
	for(int i=head[x];i;i=nex[i]){
		int y=ver[i];
		if(y==fa) continue;
		f[y]=f[x]-size[y]*2+size[1];
		dfs2(y,x);
	}
}
int sum_,k_;
void dfs_1(int x,int fa){
	d[x]=d[fa]+1;
	sum[x]=1;//size[1]的个数 
	k[x]=b[fa]-b[x];//常数 
	summ[x]=1;
	kk[x]=b[fa]-b[x];
	if(x==1){
		sum[x]=2;
		k[x]=0;
	}
	for(int i=head[x];i;i=nex[i]){
		int y=ver[i];
		if(y==fa) continue;
		dfs_1(y,x);
		sum[x]-=summ[y];
		k[x]-=kk[y];
	}
	sum_+=sum[x]*(d[x]-1);
	k_+=k[x]*(d[x]-1);
}
void clear(){
	tot=0;
	sum_=0,k_=0;
	memset(head,0,sizeof(head));
	memset(ver,0,sizeof(ver));
	memset(nex,0,sizeof(nex));
	memset(f,0,sizeof(f));
}
signed main(){
	int T;
	scanf("%lld",&T);
	while(T--){
		clear();
		int n;
		scanf("%lld",&n);
		for(int i=1;i<n;i++){
			int x,y;
			scanf("%lld%lld",&x,&y);
			add(x,y);
		}
		int op;
		scanf("%lld",&op);
	    if(op==0){
		    for(int i=1;i<=n;i++){
		      	scanf("%lld",&a[i]);  
			}
			dfs1(1,0,0);
			dfs2(1,0);
			for(int i=1;i<=n;i++){
				printf("%lld ",f[i]);
			}
			cout<<endl;
		}
		else{
			for(int i=1;i<=n;i++){
				scanf("%lld",&b[i]);
			}
			dfs_1(1,0);
			size[1]=(2*b[1]-k_)/sum_;
			for(int i=1;i<=n;i++){
				cout<<(sum[i]*size[1]+k[i])/2<<" ";
			}
			cout<<endl; 
		}
		
	}
}

#

现学的卡特兰数。
对于 typ=0 可以用组合数 C(n,i)C(i,i/2)C((ni),(ni)/2)
对于 typ=1 纯纯卡特兰数 catalan(n)=C(2n,n)C(2n,n1) 这里为n/2 的卡特兰。
对于 typ=3 就是横的卡特兰再乘上纵的卡特兰。
对于 typ=2 就要考虑dp (n2)f[i] 表示走 i 步回到原点的方案数,枚举第一次回到原点时走过的步数 j (为了存在合法解,j为偶数),则此时方案数为 f[ij]catalan((j1)/2) 注意是第一次回到。

点击查看代码
#include<iostream>
#define int long long
using namespace std;
const int mod=1e9+7;
int n,op;
int f[100050];
int dp[100050];
int mgml(int x,int p){
	int ans=1;
	while(p){
		if(p&1) ans=(ans*x)%mod;
		x=(x*x)%mod;
		p>>=1;
	}
	return ans;
}
void init(){
	f[0]=1;
	for(int i=1;i<=n;i++){
		f[i]=(f[i-1]*i)%mod;
	}
}
int c(int a,int b){
	return f[a]*mgml(f[a-b],mod-2)%mod*mgml(f[b],mod-2)%mod;
}
int ctl(int n){
	return (c(2*n,n)-c(2*n,n+1)+mod)%mod;
}
signed main(){
	cin>>n>>op;
	init();
	if(op==0){
		int ans=0;
		for(int i=0;i<=n;i++){
			if(i%2) continue;
			ans=(ans+c(n,i)%mod*c(i,i/2)%mod*c(n-i,(n-i)/2)%mod)%mod;
		}
		cout<<ans<<endl;
	}
	else if(op==1){
		cout<<ctl(n/2)<<endl;
	}
	else if(op==2){
		dp[0]=1;
		for(int i=2;i<=n;i+=2){
			for(int j=2;j<=i;j+=2){
				dp[i]=(dp[i]+dp[i-j]*ctl((j-2)/2)%mod*4%mod)%mod;
			}
		}
		cout<<dp[n]<<endl;
	}
	else{
		int ans=0,sum=0;
		for(int i=0;i<=n;i++){
			if(i%2) continue;
			ans=(ans+c(n,i)*(c(i,i/2)-c(i,i/2+1)+mod)%mod*(c(n-i,(n-i)/2)-c(n-i,(n-i)/2+1)+mod)%mod)%mod;
		}
		cout<<ans<<endl;
	}
}

作者:bloss

出处:https://www.cnblogs.com/jinjiaqioi/p/17560925.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   _bloss  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
点击右上角即可分享
微信分享提示
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu