hdu5378

关于逆元的相关知识已经总结到这里:求i模p的逆元中

还有关于这道题,在测试样例时,一直是错误的,最后才发现是求快速幂即ni函数时,其中的x没有设为long long int,谨记,虽然x乘完自己后或模上1000000007,但是还没模之前可能超过int的范围,但不会超过long long int的范围,所以要把x设为long long int。

不过关于这道题,嗯,用概率来求方法数,谁也限制不住人类的大脑啊!!!(今天学校停水,早晨没吃到牛肉馅的包子,中午懒在机房,所以吃了一天的面包,咸菜,不说了,说多了都是泪!!!我要吃肉!!!)

2015.8.29:

今天再次看着道题,一开始偷瞄到一点是通过概率求总共有多少种方法,但是死活也记不起到底该怎么求,依稀的记忆+推理得出是二维的dp,然后就死活就认准了dp[i][j]代表以i为根节点的子树中有j个minister,然后就只能朝着背包的方向去想了,最后感觉这样能做,但是不如原先的方法简单,虽然记不起原先的方法是什么了。然后打开题解,结果发现竟然看不懂了,在网上找题解,从新整理这道题,最后总算发现,不是智商问题,还算欣慰哭

题解中dp[i][j]代表1到i中有几个点在以它为根节点的子树中是最大的,那么相当于是前i个点中选择了j个让它成为以它为根节点的子树中最大的,并没有其它的含义了,不要再多想了,如果可以的话,想要冲着刚才的自己这样喊,然后递归就行了。

下面证明为什么在1到i中有j个是以它为根节点的子树中最大的,那么就只有j个minister:

首先,可以得知,这j个点必定是minister;

其次,假如说存在第j+1个minister,那么存在某个包括这个点的子树中这个点最大,任何一棵子树如果包括这个点的话,那么就肯定包括以这个点为根节点的那棵子树,所以在以这个点为根节点的子树中这个点也是最大的,与前面的假设,相违背,所以不可能存在第j+1个minister。

最后,没有最后。


#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
#define N 1010
#define MOD 1000000007

long long int dp[N][N];
int siz[N];
int head[N],to[2*N],nextedge[2*N];
int cou;
long long int A[N];

void add(int a,int b){
    to[cou]=b;nextedge[cou]=head[a];head[a]=cou++;
}

void dfs(int u,int fa){
    siz[u]=1;

    for(int i=head[u];i!=-1;i=nextedge[i]){
        int v=to[i];

        if(v==fa){
            continue;
        }
        else{
            dfs(v,u);
            siz[u]+=siz[v];
        }
    }

    return;
}

long long int ni(long long int x){
    int y=MOD-2 ;
    long long int ans=1;

    while(y){
        if(y%2){
            ans=ans*x%MOD;
        }
        y=y/2;
        x=x*x%MOD;
    }

    return ans;
}

int main(){
    int t;
    int n;
    int k;
    int a,b;

    A[0]=1;
    for(int i=1;i<N;i++){
        A[i]=A[i-1]*i%MOD;
    }

    scanf("%d",&t);
    for(int cas=1;cas<=t;cas++){
        scanf("%d%d",&n,&k);
        memset(head,-1,sizeof(head));
        cou=0;
        for(int i=1;i<n;i++){
            scanf("%d%d",&a,&b);
            add(a,b);
            add(b,a);
        }

        dfs(1,-1);

        memset(dp,0,sizeof(dp));
        dp[1][1]=ni(siz[1]);
        dp[1][0]=(siz[1]-1)*dp[1][1]%MOD;

        for(int i=2;i<=n;i++){
            long long int tempg=ni(siz[i]);
            dp[i][0]=dp[i-1][0]*(siz[i]-1)%MOD*tempg%MOD;
            for(int j=1;j<=i;j++){
                dp[i][j]=(dp[i-1][j]*(siz[i]-1)%MOD*tempg%MOD+dp[i-1][j-1]*tempg%MOD)%MOD;
            }
        }

        printf("Case #%d: %d\n",cas,(A[n]*dp[n][k]%MOD));
    }

    return 0;
}


posted @ 2015-08-13 17:41  buzhidaohahaha  阅读(220)  评论(0编辑  收藏  举报