AT3728 Squirrel Migration

AT3728 Squirrel Migration 

就是给每个点分配两个匹配点(自环除外)

考虑最大值

考虑极限情况:每个边的贡献是min(sz[u],sz[v])*2

证明存在方案:

发现,如果哪边sz更小,就把这些边都往外连

这样,在重心的位置,会两两匹配闭合。

所以存在构造方案。

 

方案数?就是最后匹配的方案

重心两个:((n/2)!)^2

重心一个:

也就是,以重心为根,每个子树是一个组,每个组必须匹配别的组

而重心自己可以连自环或者匹配任意一个组

枚举重心连自环与否,做两遍。

 

现在有若干个组,每个组有num[i]个元素,每个组不能匹配自己的元素

考虑容斥!

f[i][j]前i个组,有j个位置连了自己组的元素的方案数

f[i][j+k]+=f[i-1][j]*C(num[i],k)*A(num[i],k)

看似O(n^3),实际和树形背包的sz优化一样,就是O(n^2)的

 

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define fi first
#define se second
#define mk(a,b) make_pair(a,b)
#define numb (ch^'0')
#define pb push_back
#define solid const auto &
#define enter cout<<endl
#define pii pair<int,int>
using namespace std;
typedef long long ll;
template<class T>il void rd(T &x){
    char ch;x=0;bool fl=false;while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);(fl==true)&&(x=-x);}
template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('\n');}
namespace Modulo{
const int mod=1e9+7;
int ad(int x,int y){return (x+y)>=mod?x+y-mod:x+y;}
void inc(int &x,int y){x=ad(x,y);}
int mul(int x,int y){return (ll)x*y%mod;}
void inc2(int &x,int y){x=mul(x,y);}
int qm(int x,int y=mod-2){int ret=1;while(y){if(y&1) ret=mul(x,ret);x=mul(x,x);y>>=1;}return ret;}
}
using namespace Modulo;
namespace Miracle{
const int N=5005;
int n;
struct node{
    int nxt,to;
}e[2*N];
int hd[N],cnt;
int jie[N],inv[N];
int C(int n,int m){
    if(n<0||m<0||n<m) return 0;
    return mul(jie[n],mul(inv[m],inv[n-m]));
}
int A(int n,int m){
    return mul(C(n,m),jie[m]);
}
void add(int x,int y){
    e[++cnt].nxt=hd[x];
    e[cnt].to=y;
    hd[x]=cnt;
}
int be[N],sz[N],num[N],tot;
int rt[N];
void dfs(int x,int fa){
    sz[x]=1;
    int mx=0;
    for(reg i=hd[x];i;i=e[i].nxt){
        int y=e[i].to;
        if(y==fa) continue;
        dfs(y,x);
        sz[x]+=sz[y];
        if(sz[y]>mx) mx=sz[y];
    }
    mx=max(mx,n-sz[x]);
    if(mx<=n/2){
        rt[++rt[0]]=x;
    }
}
void fin(int x,int fa){
    be[x]=tot;
    ++num[be[x]];
    for(reg i=hd[x];i;i=e[i].nxt){
        int y=e[i].to;
        if(y==fa) continue;
        if(x==rt[1]){
            ++tot;
        }
        fin(y,x);
    }
}
int f[N][N];
int calc(){
    memset(f,0,sizeof f);
    f[0][0]=1;
    int sum=0;
    for(reg i=1;i<=tot;++i){
        // cout<<" i "<<i<<" "<<num[i]<<endl;
        for(reg j=0;j<=sum;++j){
            for(reg k=0;k<=num[i];++k){
                // cout<<" con "<<mul(f[i-1][j],mul(C(num[i],k),A(num[i],k)))<<endl;
                f[i][j+k]=ad(f[i][j+k],mul(f[i-1][j],mul(C(num[i],k),A(num[i],k))));
            }
        }
        sum+=num[i];
    }
    ll ret=0;
    for(reg j=0;j<=sum;++j){
        // cout<<f[tot][j]<<endl;
        if(j&1){
            ret=ad(ret,mod-mul(f[tot][j],jie[sum-j]));
        }else{
            ret=ad(ret,mul(f[tot][j],jie[sum-j]));
        }
    }
    return ret;
}
int main(){
    rd(n);
    jie[0]=1;
    for(reg i=1;i<=n;++i) jie[i]=mul(jie[i-1],i);
    inv[n]=qm(jie[n]);
    for(reg i=n-1;i>=0;--i) inv[i]=mul(inv[i+1],i+1);
    int x,y;
    for(reg i=1;i<n;++i){
        rd(x);rd(y);
        add(x,y);add(y,x);
    }
    dfs(1,0);
    if(rt[0]==2){
        ll ans=qm(jie[n/2],2);
        ot(ans);return 0;
    }
    // cout<<rt[1]<<endl;
    fin(rt[1],0);
    // cout<<" tot "<<tot<<endl;
    // prt(be,1,n);
    int ans=calc();
    // cout<<" ans1 "<<ans<<endl;
    num[++tot]=1;
    ans=ad(ans,calc());
    ot(ans);
    return 0;
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
*/

构造最大值,考虑上界,再证明能不能达到。

然后构造方案很明确了,方案数就是分组,容斥DP来处理

转载于:https://www.cnblogs.com/Miracevin/p/10972371.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
提供的源码资源涵盖了python应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值