zoukankan      html  css  js  c++  java
  • 6541. 【GDOI2020模拟4.4】Permutation

    题目描述


    题解

    迫真签到题

    前几天做过类似的,只不过要求的是相邻的lca,所以要n^3考虑具体每一段

    对于这题不行

    显然每个子树内的段=边权/2,并且合并时要求不能合并相同子树内的段

    容斥一下,系数是(-1)^合并相同子树内的段再乘上组合数

    假设当前不为整棵树的根,设第子树i原有p[i]段,合并后变成q[i]段,最后再合并成k段

    则贡献为

    (huge frac{sum q[i]+1}{prod q[i]!}C_{(sum q[i]+1)-1}^{k-1}prod(-1)^{p[i]-q[i]}C_{p[i]-1}^{q[i]-1})

    就是把合并完的随便放再合并成k段,注意要考虑当前节点

    手玩一下发现当合并段数>0时容斥系数之和=0,因此容斥后的会在每个节点处合并成真正的方案数

    把式子拆开背包

    如果当前是整棵树的根就硬点为第一段,最后乘上n的轮换

    code

    #include <bits/stdc++.h>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define C(n,m) (jc[n]*Jc[m]%mod*Jc[(n)-(m)]%mod)
    #define ll long long
    #define file
    using namespace std;
    
    int a[10001][3],ls[5001],size[5001],n,mod,Mod,i,j,k,l,len;
    ll f[5001],g[5001],G[5001],jc[5001],Jc[5001],w[5001],ans;
    
    ll qpower(ll a,int b) {ll ans=1;while (b) {if (b&1) ans=ans*a%mod;a=a*a%mod;b>>=1;} return ans;}
    void New(int x,int y,int z) {++len;a[len][0]=y;a[len][1]=ls[x];ls[x]=len;a[len][2]=z;}
    
    void dfs(int Fa,int t,int Ls)
    {
    	int i;
    	ll s;
    	
    	for (i=ls[t]; i; i=a[i][1])
    	if (a[i][0]!=Fa)
    	dfs(t,a[i][0],a[i][2]);
    	
    	memset(g,0,sizeof(g));g[1]=size[t]=1;
    	for (i=ls[t]; i; i=a[i][1])
    	if (a[i][0]!=Fa)
    	{
    		memset(G,0,(size[t]+size[a[i][0]]+1)*8);
    		
    		fo(j,1,size[t])
    		{
    			fo(k,1,a[i][2])
    			G[j+k]=(G[j+k]+g[j]*f[a[i][0]]%mod*((a[i][2]-k)&1?-1:1)*C(a[i][2]-1,k-1)%mod*Jc[k])%mod;
    		}
    		size[t]+=size[a[i][0]];
    		
    		memcpy(g,G,(size[t]+1)*8);
    	}
    	
    	if (Fa)
    	{fo(i,Ls,size[t]) f[t]=(f[t]+g[i]*jc[i]%mod*C(i-1,Ls-1))%mod;}
    	else
    	{fo(i,1,size[t]) ans=(ans+g[i]*jc[i-1]%mod)%mod;}
    }
    
    int main()
    {
    	freopen("permutation.in","r",stdin);
    	#ifdef file
    	freopen("permutation.out","w",stdout);
    	#endif
    	
    	scanf("%d%d",&n,&mod),Mod=mod-2;
    	jc[0]=jc[1]=Jc[0]=Jc[1]=w[1]=1;
    	fo(i,2,n) scanf("%d%d%d",&j,&k,&l),l/=2,New(j,k,l),New(k,j,l),w[i]=mod-w[mod%i]*(mod/i)%mod,jc[i]=jc[i-1]*i%mod,Jc[i]=Jc[i-1]*w[i]%mod;
    	
    	dfs(0,1,-1);
    	
    	printf("%lld
    ",(ans+mod)%mod*n%mod);
    	
    	fclose(stdin);
    	fclose(stdout);
    	
    	return 0;
    }
    
  • 相关阅读:
    WPF自定义控件
    NPOI设置Excel单元格字体、边框、对齐、背景色
    关于StreamReader.ReadToEnd方法
    ASP.NET Core Web多语言项目
    docker与虚拟机的区别
    C# Task.Run 和 Task.Factory.StartNew 区别
    MVC的SignalR例子
    深圳游玩攻略
    一个域名下多个Vue项目
    Linq的执行效率及优化
  • 原文地址:https://www.cnblogs.com/gmh77/p/12684324.html
Copyright © 2011-2022 走看看