ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

雅礼集训 2018 Day1

2022-08-31 18:01:23  阅读:167  来源: 互联网

标签:int ll db long Day1 雅礼 2018 using define


「雅礼集训 2018 Day1」树

首先发现这个期望是诈骗,我们只需要求出\(g_i\)表示深度为\(i\)的树的个数然后带权除以总方案数即可。

树的题目容易想到一个子树一个子树抠出来,设\(f_{i,j}\)表示有\(i\)个点,深度为\(j\)的方案数,容易发现二号节点的父亲一定是\(1\),因此可以枚举二号节点的子树大小以及深度,然后暴力转移即可。时间复杂度\(O(n^4)\)。

进一步的,发现转移形式中对两个深度取max,因此可以拆了做到\(O(n^3)\)但似乎跑得差不多快。

四舍五入啥的用个__int128啥就好了。

code:

#include<bits/stdc++.h>
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((m)*(x-1)+(y))
#define R(n) (rnd()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;
using namespace std;const int N=24+5,M=pow(6,10)+5,K=2e3+5,mod=1e9+7,Mod=mod-1;const db eps=1e-5;const int INF=1e9+7;
int n,p,x,y,z;__int128 dp[N][N],C[N][N];lb Ans;ll Ts;
ll mpow(ll x,int y,int p){ll Ans=1;while(y) y&1&&(Ans=Ans*x%p),y>>=1,x=x*x%p;return Ans;}
int main(){
	//freopen("1.in","r",stdin);
	int i,j,x,y;scanf("%d%d",&n,&p);dp[1][1]=1;for(i=0;i<=n;i++) for(C[i][0]=j=1;j<=i;j++) C[i][j]=C[i-1][j]+C[i-1][j-1];
	for(i=2;i<=n;i++){
		for(j=1;j<i;j++){
			for(x=1;x<=j;x++) for(y=1;y<=i-j;y++) dp[i][max(x,y+1)]+=dp[j][x]*dp[i-j][y]*C[i-2][j-1];
		}
	}
	for(i=1;i<=n;i++) Ans+=dp[n][i]*i,Ts=(Ts+dp[n][i]*i)%p;
	for(i=1;i<n;i++) Ans/=i,Ts=Ts*mpow(i,p-2,p)%p;printf("%d\n%lld\n",(int)(Ans+0.5),Ts);
}

「雅礼集训 2018 Day1」仙人掌

人傻常数大喜提最劣解了属于是。

首先显然先建个圆方树,然后讨论圆点向方点,以及方点向原点的转移。

发现圆方树上每个点和祖先最多有两条边的关系,因此设\(f_{x,0/1/2}\)表示\(x\)点向祖先至少可以连\(0/1/2\)条边的方案数。

圆点向方点的转移是平凡的,只需要枚举第一个点和环的顶点的边的连接情况,然后设\(g_{i,0/1}\)表示\(i-1\)向\(i\)点有没有边,最后可以计算出顶点和下面的点有几条边相连,因为每条边只会被计算一次,时间复杂度\(O(n)\)。

方点向原点的转移可以跑一个背包算出\(h_{x,i}\)表示\(x\)这个点和子树内连了\(i\)条边,然后根据定义算出\(f_x\),不过是\(O(nA)\)的。发现每个点的三个系数只会贡献一次,于是直接分治+NTT卷起来就可以算出\(h\)。这样是\(O(n\log^2n)\),随便过。

code:

#include<bits/stdc++.h>
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((m)*(x-1)+(y))
#define R(n) (rnd()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;
using namespace std;const int N=200000+5,M=(1<<18),K=2e3+5,mod=998244353,Mod=mod-1;const db eps=1e-5;const int INF=1e9+7;
int n,m,A[N],cnt,x,y,B[N],Bh,Fl[N],H;ll f[N][3],g[2],p[2],E[N];struct Edge{int to,w;};vector<Edge> S[N];
vector<int> G[N],Id[N];void con(int x,int y){/*cerr<<x<<' '<<y<<'\n';*/G[x].PB(y);G[y].PB(x);}
namespace Tarjan{
	int dfn[N],low[N],st[N],sh,dh;void Tarjan(int x,int La){
		dfn[x]=low[x]=++dh;st[++sh]=x;for(Edge i:S[x]) {if(i.w==La) continue;
			if(dfn[i.to]) {low[x]=min(low[x],dfn[i.to]);continue;}Tarjan(i.to,i.w);low[x]=min(low[x],low[i.to]);
			if(dfn[x]<=low[i.to]){++cnt;Fl[cnt]=(dfn[x]==low[i.to]);con(cnt,x);Id[cnt].PB(x);while(st[sh+1]^i.to) con(cnt,st[sh]),Id[cnt].PB(st[sh]),sh--;}
		}
	}
}
ll mpow(ll x,int y=mod-2){ll Ans=1;while(y) y&1&&(Ans=Ans*x%mod),y>>=1,x=x*x%mod;return Ans;}
namespace Poly{const int g=3,Invg=mpow(g);
	int k,tr[M];ll A[M],C[M],D[M];void Init(int n){for(k=1;k<=n;k<<=1);for(int i=0;i<k;i++) tr[i]=(tr[i>>1]>>1)|((i&1)?k/2:0),C[i]=D[i]=0;}
	void NTT(ll *A,int n,int Fl){
		int i,j,h;ll pus,now,key;for(i=0;i<n;i++) i<tr[i]&&(swap(A[i],A[tr[i]]),0);for(i=2;i<=n;i<<=1){
			for(key=mpow(Fl?g:Invg,(mod-1)/i),j=0;j<n;j+=i) for(pus=1,h=j;h<j+i/2;h++) now=A[h+i/2]*pus%mod,A[h+i/2]=(A[h]-now+mod)%mod,A[h]=(A[h]+now)%mod,pus=pus*key%mod;
		}if(Fl) return;ll Invn=mpow(n);for(i=0;i<n;i++) A[i]=A[i]*Invn%mod;
	}
	void Solve(int l,int r){if(l==r) return;
		int m=l+r>>1,i;Solve(l,m);Solve(m+1,r);Init(2*(r-l+1)+1);for(i=3*l-3;i<=3*l-3+(m-l+1)*2;i++) C[i-3*l+3]=E[i],E[i]=0;for(i=3*(m+1)-3;i<=3*(m+1)-3+(r-m)*2;i++) D[i-3*(m+1)+3]=E[i],E[i]=0;
		NTT(C,k,1);NTT(D,k,1);for(i=0;i<k;i++) C[i]=(C[i]*D[i])%mod;NTT(C,k,0); for(i=0;i<=2*(r-l+1);i++) E[i+3*l-3]=C[i];
	}
}
void DP(int x,int La){
	if(x<=n){H=1;E[0]=1;for(int i:G[x]) i^La&&(DP(i,x),0);
		H=1;E[0]=1;for(int i:G[x]) i^La&&(++H,E[H*3-3]=f[i][1+Fl[i]],E[H*3-2]=f[i][Fl[i]],E[H*3-1]=(Fl[i]?f[i][0]:0));Poly::Solve(1,H);
		for(int i=0;i<=min(A[x]-2,2*H);i++) f[x][2]+=E[i];f[x][2]%=mod;f[x][1]=(f[x][2]+E[A[x]-1])%mod;f[x][0]=(f[x][1]+E[A[x]])%mod;for(int i=0;i<=2*H;i++) E[i]=0;
	}else{for(int i:G[x]) i^La&&(DP(i,x),0);
		int Tp=0,i,h,j;for(i=0;i<Id[x].size();i++) if(Id[x][i]==La)Tp=i; Bh=0;for(i=Tp+1;i<Id[x].size();i++) B[++Bh]=Id[x][i];for(i=0;i<Tp;i++) B[++Bh]=Id[x][i];
		Me(g,0);g[0]=1;for(i=1;i<=Bh;i++) for(Mc(p,g),Me(g,0),j=0;j<2;j++) for(h=0;h<2;h++) g[h]=(g[h]+p[j]*f[B[i]][j+(!h)])%mod;f[x][0]=g[1];f[x][1]=g[0];
		if(Fl[x]){Me(g,0);g[1]=1;for(i=1;i<=Bh;i++) for(Mc(p,g),Me(g,0),j=0;j<2;j++) for(h=0;h<2;h++) g[h]=(g[h]+p[j]*f[B[i]][j+(!h)])%mod;f[x][1]=(g[1]+f[x][1])%mod;f[x][2]=g[0];}
	}
}
int main(){
	freopen("1.in","r",stdin);
	int i,j;scanf("%d%d",&n,&m);cnt=n;for(i=1;i<=m;i++) scanf("%d%d",&x,&y),S[x].PB((Edge){y,i}),S[y].PB((Edge){x,i});Tarjan::Tarjan(1,0);
	for(i=1;i<=n;i++) scanf("%d",&A[i]);DP(1,0);printf("%lld\n",f[1][0]);
}

「雅礼集训 2018 Day1」图

先考虑图的结构与点的颜色固定时的交错路径数奇偶性。设\(f_i\)为考虑到\(i\)点的奇偶性,则枚举所有有边的\(v\),有\(f_i=f_{i-1}\operatorname{xor}\limits{f_v}\operatorname{xor}1\)。

我们发现只能是这个点开始的路径数为奇数能对答案造成贡献,则我们设\(dp_{i,x,y,p}\)表示到\(i\)点,有\(x\)个白色点是奇数路径数,有\(y\)个黑点是奇数路径数的奇偶性为\(p\)的方案数。这样是\(O(n^3)\)的。

但是,这个状态数真的有必要吗,我们发现只要转移黑点的时候,\(x\)有值的转移是固定的,因此可以设\(dp_{i,0/1,0/1,0/1}\)表示有无奇数路径数白点,有无奇数路径数黑点,奇偶性为\(0/1\)的方案数。随便转移,时间复杂度\(O(n)\)

code:

#include<bits/stdc++.h>
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((m)*(x-1)+(y))
#define R(n) (rnd()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;
using namespace std;const int N=200000+5,M=pow(6,10)+5,K=2e3+5,mod=998244353,Mod=mod-1;const db eps=1e-5;const int INF=1e9+7;
int n,m,k,op,A[N],z;ll f[2][2][2],g[2][2][2],Po[N],Ans;
int main(){
	//freopen("1.in","r",stdin);
	int i,j,x,y;scanf("%d%d",&n,&op);f[0][0][0]=1;for(Po[0]=i=1;i<=n;i++) {
		Po[i]=Po[i-1]*2%mod;scanf("%d",&z);Mc(g,f);Me(f,0);for(j=0;j<2;j++){
			for(x=0;x<2;x++){
				for(y=0;y<2;y++) {if(!g[j][x][y]) continue;
					if(z){
						if(x) f[j][x][y]=(f[j][x][y]+Po[i-2]*g[j][x][y])%mod,f[j^1][x][y|1]=(f[j^1][x][y|1]+Po[i-2]*g[j][x][y])%mod;
						else f[j^1][x][y|1]=(f[j^1][x][y|1]+g[j][x][y]*Po[i-1])%mod;
					}
					if(z^1){
						if(y) f[j][x][y]=(f[j][x][y]+Po[i-2]*g[j][x][y])%mod,f[j^1][x|1][y]=(f[j^1][x|1][y]+Po[i-2]*g[j][x][y])%mod;
						else f[j^1][x|1][y]=(f[j^1][x|1][y]+g[j][x][y]*Po[i-1])%mod;
					}
				}
			}
		}
	}for(i=0;i<2;i++) for(j=0;j<2;j++) Ans+=f[op][i][j];printf("%lld\n",Ans%mod);
}

标签:int,ll,db,long,Day1,雅礼,2018,using,define
来源: https://www.cnblogs.com/275307894a/p/16644046.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有