• WC2019 数树


    Task 0

    判断有多少条相同边即可。

    复杂度(O(N))

    namespace Subtask1{
    	pair<int,int> e1[N],e2[N];
    	void Main(int n,int y){
    		for(int i=1,u,v;i<n;i++){
    			scanf("%d%d",&u,&v);
    			e1[i] = pair<int,int> (min(u,v), max(u,v));
    		}
    		for(int i=1,u,v;i<n;i++){
    			scanf("%d%d",&u,&v);
    			e2[i] = pair<int,int> (min(u,v), max(u,v));
    		}
    		sort(e1+1,e1+n),sort(e2+1,e2+n);
    		int j = 1,B = n;
    		for(int i=1;i<n;i++){
    			while(j<n&&e2[j]<e1[i])++j;
    			if(j<n && e2[j] == e1[i]) B--;
    		}
    		cout << qpow(y,B) << endl;
    	}
    }
    

    Task 1

    考虑prufer序列,如果硬点了一些边一定被重复覆盖,那么硬点这(c)个联通块的方案是:

    [n^{c-2} prod siz_i ]

    考虑系数,硬点了(a)条边会在硬点(b)条边中出现了(inom{a}{b})次,恰好(a)条边的贡献是(y^{n-a})

    考虑:

    [sum _iinom {A}{i} x^i = (x+1)^A ]

    那么系数设置为(y^{-1}-1)时,正好会贡献(y^{-A})

    (siz)的贡献拆组合意义,即:每个连通块内都要选一个节点作为代表。

    (f[x][0/1])表示当前节点所在连通块是否选了代表。

    复杂度$O(n) $

    namespace Subtask2{
    	int hed[N],to[N<<1],nxt[N<<1],cnt;
    	inline void adde(int u,int v){++cnt;to[cnt]=v,nxt[cnt]=hed[u];hed[u]=cnt;}
    	int f[N][2],Val;
    	inline void dfs(int x,int pre){
    		f[x][1] = n, f[x][0] = 1;
    		for(int i=hed[x];i;i=nxt[i]){
    			int v=to[i];if(v==pre)continue;
    			dfs(v,x);int f1=0,f0=0;
    			f1 = add(mul(f[x][1], add(mul(Val,f[v][0]),f[v][1])), mul(mul(Val, f[x][0]), f[v][1]));
    			f0 = mul(f[x][0], add(mul(Val, f[v][0]),f[v][1]));
    			f[x][1] = f1, f[x][0] = f0;
    		}
    	}
    
    	void Main(int n,int y){
    		for(int i=1,u,v;i<n;i++){
    			scanf("%d%d",&u,&v);
    			adde(u,v),adde(v,u);
    		}Val = sub(qpow(y,mod-2),1);
    		dfs(1,0);
    		// cout << mul(f[1][1], qpow(9,mod-2)) << endl;
    		printf("%d
    ",mul(qpow(1ll*n*n%mod,mod-2),mul(qpow(y,n), f[1][1])));
    	}
    }
    

    Task 2

    容斥系数和以上一样,(f[i])表示(i)个点的连通块的贡献。现在要枚举的树是两颗树,所以方案的贡献要平方。

    写成(EGF)之后(exp)就行了。

    (O(nlog n))

    namespace Subtask3{
    	using namespace Template_Poly;
    	Poly f;
    	int ifac[N], fac[N], Val;
    	inline void init(int n = 1e5){
    		fac[0] = ifac[0] = 1;for(int i=1;i<=n;i++)fac[i] = mul(fac[i-1], i);
    		ifac[n] = qpow(fac[n], mod-2);for(int i=n-1;i;i--)ifac[i] = mul(ifac[i+1], i+1);
    	}
    	inline void initf(int n){
    		f.resize(n+1);
    		for(int i=1,w = 1;i<=n;i++, w = mul(w, Val)){
    			f[i] = w;f[i] = mul(f[i], mul(qpow(i,max(0,i-2)), 1ll*n*n%mod));
    			f[i] = mul(f[i], 1ll*i*i%mod);
    			f[i] = mul(f[i], ifac[i]);
    		}
    	}
    	void Main(int n,int y){
    		Val = sub(qpow(y,mod-2),1);
    		init();initf(n);
    		f = exp(f);
    		int ans = mul(f[n],fac[n]);
    		ans = mul(ans, qpow(1ll*n*n%mod*n%mod*n%mod,mod-2));
    		ans = mul(ans, qpow(y,n));
    		cout << ans << endl;
    	}
    }
    
  • 相关阅读:
    设备管理器里“SM总线控制器”、“其它PCI桥设备”驱动有问题
    MapReduce实现两表的Join--原理及python和java代码实现
    Calendar类经常用法 日期间的转换 set方法有巨坑
    Java 装饰模式(4.4)
    LoadRunner访问Mysql数据库(转)
    linux下定时执行任务的方法
    docker 常用命令
    Docker exec与Docker attach
    docker容器跨服务器的迁移方式export和save(转)
    cpu时间 / cpu利用率计算
  • 原文地址:https://www.cnblogs.com/weiyanpeng/p/11598480.html
Copyright © 2020-2023  润新知