2 条题解

  • 0
    @ 2017-11-07 09:23:52

    分别算出一条边将原树分割成两个子树,然后用排列组合求出所有k个点在其中一棵子树(不需要这条边),或者小于k个点在这一个子树(需要这条边)的所有情况之和。
    预处理好阶乘step,再进行如下变形(1e9+7是素数,所以直接用费马小定理啦)
    C(num[p],i)%mod
    =num[p]!/(i!*(num[p]-i)!)%mod
    =num[p]!/(i!*(num[p]-i))*(i!*(num[p]-i)!)^(mod-1)%mod
    =num[p]!*(i!*(num[p]-i)!)^(mod-2)%mod=num[p]!*fast_pow(i!*(num[p]-i)!,mod-2)%mod
    =step[num[p]]*fast_pow(step[i]*(num[p]-i)%mod,mod-2)%mod;
    标程

    #include<bits/stdc++.h>
    #define LL long long
    const LL mod=1e9+7;
    inline void read(LL &a)
    {
        a=0;char c=getchar();
        while(c<'0'||c>'9')c=getchar();
        while(c>='0'&&c<='9')
        {
            a=(a<<1)+(a<<3)+c-'0';
            c=getchar();
        }
    }
    inline void write(LL a)
    {
        if(a<0){putchar('-');a=-a;}
        if(a>9)write(a/10);
        putchar(a%10+'0');
    }
    #define maxn 2001
    LL ans=0,n,k,d=0,num[maxn],point[maxn],next[maxn],to[maxn],father[maxn],step[maxn];
    inline void add(LL a,LL b)
    {
        next[++d]=point[a];
        point[a]=d;
        to[d]=b;
    }
    inline LL fast_pow(LL a,LL b)
    {
        LL base=a,ans=1;
        while(b)
        {
            if(b&1)ans=ans*base%mod;
            base=base*base%mod;
            b>>=1;
        }
        return ans;
    }
    inline LL dfs1(LL p)
    {
        LL side=point[p];
        num[p]=1;
        while(side)
        {
            if(to[side]!=father[p])
            {
                father[to[side]]=p;
                num[p]+=dfs1(to[side]);
            }
            side=next[side];
        }
        return num[p];
    }
    inline LL C(LL m,LL n)
    {
        return step[m]*fast_pow(step[n]*step[(m-n)]%mod,mod-2)%mod;
    }
    inline void dfs2(LL p)
    {
        for(LL i=1;i<=k&&i<=num[p];i++)
            if(k-i<=n-num[p]&&k-i)
                ans=(ans+C(num[p],i)*C(n-num[p],k-i)%mod)%mod;
        LL side=point[p];
        while(side)
        {
            if(to[side]!=father[p])dfs2(to[side]);
            side=next[side];
        }
    }
    int main()
    {
        read(n);read(k);
        LL st=1; 
        step[0]=1;
        for(LL i=1;i<=n;i++)st=step[i]=i*st%mod;
        memset(num,0,sizeof(num));
        memset(point,0,sizeof(point));
        LL u,v;
        for(LL i=1;i<=n-1;i++){read(u);read(v);add(u,v);add(v,u);}
        dfs1(1);
        dfs2(1);
        write(ans);
        return 0;
    }
    

    这是用扩展欧几里得求逆元,感谢Takami同学提供标程!(虽然他沒同意)

    #include <stdio.h>
    #include <iostream>
    typedef long long ll;
    const int maxn = 1005;
    using namespace std;
    const int mod = 1e9+7;
    int n,k;
    ll fact[maxn];
    inline void exgcd(int a,int b,int &x,int &y) {
        if(!b) {
            x = 1,y = 0;
            return;
        }
        exgcd(b,a%b,y,x);
        y-=x*(a/b);
    }
    int ni(int a) {
        int x,y;
        exgcd(a,mod,x,y);
        while(x<0) x+=mod;
        return x;
    }
    struct edge {
        int a,b;
        int right,left;
    } edges[maxn];
    int head[maxn],nex[maxn<<1],dis[maxn<<1],q;
    inline void connect(int x,int y) {
        nex[++q] = head[x],head[x] = q,dis[q] = y;
        nex[++q] = head[y],head[y] = q,dis[q] = x;
    }
    int cloc,in[maxn],out[maxn],fa[maxn];
    void dfs(int a,int father) {
        fa[a] = father;
        in[a] = ++cloc;
        for(int i = head[a]; i; i = nex[i]) {
            int to = dis[i];
            if(to!=father)
                dfs(to,a);
        }
        out[a] = cloc;
    }
    int c(ll a,ll b) {
        return 1l*((1ll*fact[a]%mod*ni(fact[b])%mod)%mod)*ni(fact[a-b])%mod;
    }
    int mem[maxn][maxn];
    int solve(ll a,ll b) {
        if(mem[a][b]) return mem[a][b];
        int ret = 0;
        for(int i = 1; i<=max(a,b); i++) {
            if(k-i<=b&&k-i>=1&&i<=a) {
                ret  = (ret+ 1ll*c(a,i)*c(b,k-i)%mod)%mod;
            }
        }
        mem[a][b] = mem[b][a] = ret;
        return ret;
    }
    int main() {
        cin>>n>>k;
        for(int i  =1; i<=n-1; i++) {
            int x,y;
            cin>>x>>y;
            edges[i].a = x,edges[i].b = y;
            connect(x,y);
        }
        fact[0] = 1;
        for(int i = 1; i<=n; i++)fact[i] = fact[i-1]*i%mod;
        int ans = 0;
        dfs(1,1);
        for(int i = 1; i<=n-1; i++) {
            edge &ed = edges[i];
            if(fa[ed.a]!=ed.b) swap(ed.a,ed.b);
            ed.right = out[ed.a]-in[ed.a]+1;
            ed.left = n -ed.right;
            ans=(ans+solve(ed.right,ed.left))%mod;
        }
        cout<<ans;
        return 0;
    }
    
  • 0
    @ 2017-10-07 19:48:13

    数据生成器
    #include<bits/stdc++.h>
    inline const void write(int a)
    {
    if(a>9)write(a/10);
    putchar(a%10+'0');
    }
    int belong[1001];
    inline const int check(int a)
    {
    if(belong[a]==a)return a;
    return belong[a]=check(belong[a]);
    }
    int main()
    {
    freopen(".in","w",stdout);
    srand(time(NULL));
    int n=rand()%1001;
    write(n);printf("\n");
    for(int i=1;i<=n;i++)belong[i]=i;
    for(int i=1;i<=n-1;i++)
    {
    while(true)
    {
    int u=0,v=0;
    while(!u)u=rand()%(n+1);while(!v)v=rand()%(n+1);
    if(check(u)!=check(v))
    {
    write(u);putchar(' ');write(v);printf("\n");
    belong[check(u)]=v;
    break;
    }
    }
    }
    return 0;
    }

  • 1

信息

难度
9
分类
(无)
标签
(无)
递交数
8
已通过
2
通过率
25%
上传者