首页 > 其他分享 >【XSY3338】game(期望,点分治,FFT)

【XSY3338】game(期望,点分治,FFT)

时间:2022-10-30 11:12:35浏览次数:41  
标签:连通 ch dist limits int sum FFT XSY3338 game

题面

game

题解

首先可以看出 “等概率选连通块->连通块内等概率选点” 相当于 “全局等概率选点”。

一开始感觉无从下手,但是题目中还是给了一点提示。

题目让我们输出答案乘 \(n!\) 后的结果,于是想到枚举一个 \(1\sim n\) 的排列 \(p_i\) 表示依次选择并删除的点的序列。那么对于某一个特定的 \(p_i\),这种删点方法中所有点被捶的总次数等于 \(\sum\limits_{i=1}^n (p_i所在连通块还剩下的点数)\)。

转换一下角度,考虑每个点会被捶多少次。于是所有点被捶的总次数又可以表示为:\(\sum\limits_{i=1}^n\sum\limits_{j=1}^n[删除p_j前p_j与p_i仍连通]=\sum\limits_{i=1}^n\sum\limits_{j=1}^n[删除j前j与i仍连通]\)。

其中 “删除j前j与i仍连通” 可以巧妙地转化为 “\(i\) 到 \(j\) 路径上所有点在 \(p\) 序列中出现的位置(相当于被删除的时间)都比 \(j\) 后”,即如果设 \(t_{p_i}=i\),就有 \(t_j=\min\limits_{v\in path(i,j)}t_v\),其中 \(path(i,j)\) 表示 \(i\) 到 \(j\) 的路径。

考虑某个点 \(i\) 在所有 \(p\) 的排列中被捶的总次数,这之中 \(t_j=\min\limits_{v\in path(i,j)}t_v\) 的概率是 \(\dfrac{1}{dist(i,j)}\),其中 \(dist(i,j)\) 表示 \(path(i,j)\) 集合的大小,即 \(i\) 到 \(j\) 路径上的总点数。

于是我们要求的就是 \(\sum\limits_{i=1}^n\sum\limits_{j=1}^n\dfrac{1}{dist(i,j)}\)。

对于每一个 \(dis\in [1,n]\) 求出 \(dist(i,j)=dis\) 的点对 \((i,j)\) 数,使用点分治+FFT即可。

#include<bits/stdc++.h>

#define LN 19
#define N 100010
#define INF 0x7fffffff

using namespace std;

namespace modular
{
	const int mod=1000000007;
	inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
	inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
	inline int mul(int x,int y){return 1ll*x*y%mod;}
}using namespace modular;

inline int poww(int a,int b)
{
	int ans=1;
	while(b)
	{
		if(b&1) ans=mul(ans,a);
		a=mul(a,a);
		b>>=1;
	}
	return ans;
}

inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^'0');
		ch=getchar();
	}
	return x*f;
}

const double pi=acos(-1);

typedef vector<int> poly;

struct Complex
{
	double x,y;
	Complex(){};
	Complex(double a,double b){x=a,y=b;}
}F[N<<2],w[LN][N<<2][2];

Complex operator + (Complex a,Complex b){return Complex(a.x+b.x,a.y+b.y);}
Complex operator - (Complex a,Complex b){return Complex(a.x-b.x,a.y-b.y);}
Complex operator * (Complex a,Complex b){return Complex(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}

int n;
int cnt,head[N],nxt[N<<1],to[N<<1];
int nn,rt,maxn,size[N],fa[N];
int sum[N<<1];
bool vis[N];

void init(int limit)
{
	for(int bit=0,mid=1;mid<limit;bit++,mid<<=1)
	{
		Complex gn(cos(pi/mid),sin(pi/mid));
		Complex ign(cos(pi/mid),-sin(pi/mid));
		Complex g(1,0),ig(1,0);
		for(int j=0;j<mid;j++,g=g*gn,ig=ig*ign)
			w[bit][j][0]=g,w[bit][j][1]=ig;
	}
}

void adde(int u,int v)
{
	to[++cnt]=v;
	nxt[cnt]=head[u];
	head[u]=cnt;
}

void getsize(int u,int fa)
{
	size[u]=1;
	for(int i=head[u];i;i=nxt[i])
	{
		int v=to[i];
		if(vis[v]||v==fa) continue;
		getsize(v,u);
		size[u]+=size[v];
	}
}

void getroot(int u,int fa)
{
	int nmax=0;
	for(int i=head[u];i;i=nxt[i])
	{
		int v=to[i];
		if(vis[v]||v==fa) continue;
		getroot(v,u);
		nmax=max(nmax,size[v]);
	}
	nmax=max(nmax,nn-size[u]);
	if(nmax<maxn) rt=u,maxn=nmax;
}

int maxdis;

void getdis(int u,int fa,int dis)
{
	F[dis].x++;
	maxdis=max(maxdis,dis);
	for(int i=head[u];i;i=nxt[i])
	{
		int v=to[i];
		if(vis[v]||v==fa) continue;
		getdis(v,u,dis+1);
	}
}

int rev[N<<2];

void FFT(Complex *a,int limit,int opt)
{
	opt=(opt<0);
	for(int i=0;i<limit;i++)
		rev[i]=(rev[i>>1]>>1)|((i&1)*(limit>>1));
	for(int i=0;i<limit;i++)
		if(i<rev[i]) swap(a[i],a[rev[i]]);
	for(int bit=0,mid=1;mid<limit;bit++,mid<<=1)
	{
		for(int i=0,len=mid<<1;i<limit;i+=len)
		{
			for(int j=0;j<mid;j++)
			{
				Complex x=a[i+j],y=w[bit][j][opt]*a[i+mid+j];
				a[i+j]=x+y,a[i+mid+j]=x-y;
			}
		}
	}
	if(opt)
		for(int i=0;i<limit;i++)
			a[i].x/=limit;
}

void calc(int u,int dis,int tag)
{
	maxdis=0,getdis(u,0,dis);
	int limit=1;
	while(limit<=(maxdis<<1)) limit<<=1;
	FFT(F,limit,1);
	for(int i=0;i<limit;i++)
		F[i]=F[i]*F[i];
	FFT(F,limit,-1);
	for(int i=0;i<limit;i++) sum[i+1]+=tag*(int)(F[i].x+0.5);
	for(int i=0;i<limit;i++) F[i]=Complex(0,0);
}

void solve(int u)
{
	vis[u]=1;
	calc(u,0,1);
	for(int i=head[u];i;i=nxt[i])
	{
		int v=to[i];
		if(vis[v]) continue;
		calc(v,1,-1);
		getsize(v,0);
		nn=size[v],maxn=INF,getroot(v,0);
		fa[rt]=u;
		solve(rt);
	}
}

int main()
{
	n=read();
	int limit=1;
	while(limit<=(n<<1)) limit<<=1;
	init(limit);
	for(int i=1;i<n;i++)
	{
		int u=read(),v=read();
		adde(u,v),adde(v,u);
	}
	getsize(1,0);
	nn=size[1],maxn=INF,getroot(1,0);
	solve(rt);
	int fac=1;
	for(int i=1;i<=n;i++) fac=mul(fac,i);
	int ans=0;
	for(int i=1;i<=n;i++)
		ans=add(ans,mul(sum[i],poww(i,mod-2)));
	printf("%d\n",mul(ans,fac));
	return 0;
}
/*
3
1 2
2 3
*/

标签:连通,ch,dist,limits,int,sum,FFT,XSY3338,game
From: https://www.cnblogs.com/ez-lcw/p/16840753.html

相关文章

  • matlab 中fft的用法
    一.调用方法X=FFT(x);X=FFT(x,N);x=IFFT(X);x=IFFT(X,N)用MATLAB进行谱分析时注意:(1)函数FFT返回值的数据结构具有对称性。例:N=8;n=0:N-1;xn=[43267890];Xk=fft(xn)→Xk......
  • 【HNOI2017】礼物(FFT)
    显然,\(y_i\)加上\(c\)可以看成是\(x_i\)减去\(c\)。所以就变成了\(x_i\)加上一个整数(可正可负)。现将\(x\)环拆成一个长度为\(2n\)的序列\(a\)(复制一遍),把\(......
  • 【CF553E】Kyoya and Train(期望dp,SPFA,FFT)
    考虑dp。发现正着dp好像不太好做,毕竟初值不太好设,而且时间一大于\(t\)费用就要加上\(x\),所以考虑倒着dp。设\(f_{u,j}\)表示现在已经到达\(u\)点,耗时\(j\),问......
  • GameObject 游戏物体
    游戏物体查找定义公共变量,将要查找的游戏物体拖入GameObject.Find("要查找的游戏物体名称");通过游戏物体名称查找GameObject.FindGameObjectWithTag("游戏物体的标签......
  • 网狐荣耀版游戏服务器出现 MDM_GF_GAME 游戏命令返回 false
     代码已提交:https://pan.baidu.com/s/1kKR-vieIzkagcjmYcG75KQ 提取码:4dxt 这个问题是因为游戏服务端的命令定义和客户端不一致,一般发生在移动端lua脚本里的命令和......
  • LeetCode_Array_55. Jump Game (C++)
    目录​​1,题目描述​​​​2,解题思路​​​​3,代码【C++】​​​​4,运行结果​​1,题目描述Givenanarrayofnon-negativeintegers,youareinitiallypositionedatthe......
  • 博弈论 Game Theory
    GameTheory概述等边际原理:最优的资源配置必须资源在每种用途上的边际贡献都需相等羊群效应:大家做什么,自己也跟着做什么,不管对错社会的基本问题:协调问题、合作问题协调......
  • Natural Number Game
    因为用Verilog会有颜色显示,所以用的Verilog。记录一下NaturalNumberGame的答案,好久以前做的,但没做完。目录TutorialworldAdditionworldMultiplicationworldFun......
  • D - Div Game -- ATCODER
    D-DivGamehttps://atcoder.jp/contests/abc169/tasks/abc169_d参考:https://blog.csdn.net/justidle/article/details/106474626 思路计算n中所有质数的幂,No......
  • fft
    重新改了一下板子抄起来比较短#include<bits/stdc++.h>usingnamespacestd;#definerep(i,h,t)for(inti=h;i<=t;i++)#definedep(i,t,h)for(inti=t;i>=h;i--......