其他分享
首页 > 其他分享> > 雅礼集训 2018 Day1

雅礼集训 2018 Day1

作者:互联网

「雅礼集训 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