逆元+树形dp-memset-hdu4661-Message Passing


题意:有一棵树,每个节点有一个值,每操作一次,就能把当前节点拥有的值复制到另一个节点上去。经过最少的操作次数,就可以所有n个节点上拥有n个值,问方案数。


解答:

1、啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊

没什么我只是叫一下。

首先,最优的方案肯定是把所有n个节点的值都先复制到某一个节点上面去。

因为假如你现在有三个值,1,2,3.现在有一个节点有1和2,另一个节点有1,最后一个节点有3.那么最后一个节点如果复制给第一个节点,那就满足“所有n个节点的值都先复制到某一个节点”,如果最后一个节点复制到第二个节点,那么最后总要复制一次到节点1上的,所以“所有n个节点的值都先复制到某一个节点”肯定是最优的策略。


2、那就需要遍历一遍所有的节点,把节点当作根节点,算出这个节点收到所有信息的方案数r,然后发送出去的方案数肯定也是r,那么一个节点就有r^2种方案,把所有节点作为根节点的方案数累加起来就是最终的结果。


3、那么每个节点的方案数=孩子1的方案数×孩子2的方案数…… × (所有子树节点的阶乘/(孩子1所有子树节点的阶乘×孩子2所有子树节点的阶乘×……))


4、这样子的话只用把一个节点作为根节点,算出它的dp值。然后算他第一个孩子的根节点的时候,就可以把父亲节点当作一个孩子节点。那么父亲节点的dp值就是除去当前节点得到的dp值。

父亲节点除去当前节点的其他孩子得到的dp值 = dp【父亲】 × (n-1-当前节点子树节点的个数)! × (当前节点子树的个数)! / (dp【当前节点】 × (n-1)!)

当前节点的方案数 = 父亲节点除去当前节点的其他孩子得到的dp值 × 当前节点孩子1的方案数 × 当前节点孩子2的方案数 …… × (( n-1)的阶乘/ (   (孩子1所有子树节点的阶乘×孩子2所有子树节点的阶乘×……)× (n-当前节点的子树个数)的阶乘)     )




求逆元

首先,想求的肯定是(a/b)mod m的值。

(a/b)mod m 并不等于 (a mod m)/(b mod m)

问题转换为求(a × b^(-1) )mod m 的值

那么只要m是质数就可以使用费马小定理:


b^(-1) = ( b ^ (m-2) )mod m


还有一个知道b 和 m ,通过扩展欧几里得求逆元的方法:


int extgcd(int a, int b, int& x, int& y){
  int d = a;
  if (b != 0){
    d = extgcd(b,a%b,y,x);
    y -= (a/b) *x;
  }else{
    x = 1; y = 0;
  }return d;
}



int mod_inverse (int a, int m){
  int x,y;
  extgcd(a,m,x,y);
  return (m + x %m) %m;
}//知道b和m。给它一个b和一个m,返回b的逆元


关于递归爆栈问题


手工栈的写法

微软的编译器(C++)

#pragma comment(linker, "/STACK:102400000,102400000")

G++

    int size = 256 << 20; // 256MB
    char *p = (char*)malloc(size) + size;
    __asm__("movl %0, %%esp\n" :: "r"(p));




话说在http://blog.csdn.net/liguan1/article/details/9925611 的博客看到了求逆元的一行写法

在http://www.cnblogs.com/sbaof/p/3264911.html 的博客看到了求头文件的方法




这题我用memset整个数组超时,然后改成memset部分数组/fill部分数组/for循环部分数组 都可以ac

但我以前有一道题用for循环超时,用memset数组才过的。而且memset整个数组可能预估错误memset少了,然后wa到死。


#pragma comment(linker, "/STACK:102400000,102400000")
//在dfs的时候会有递归。有递归就会用到c++自带的栈。会爆栈
//#include<bits/stdc++.h>//啊我去在国内oj中,poj,hdu 不支持这个函数,其他国外的oj,还有台湾的oj都支持,CF,Topcoder也都支持
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

#define SIZE_A 4000005
#define SIZE_N 1000005
#define MOD 1000000007
using namespace std;
struct pp
{
    int to,next;
}pra[SIZE_A];

int e,head[SIZE_A];
int n;
void init()//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
{
    e = 0;
    //fill(head,head+ 2 * n + 5, -1);
    /*for (int i = 0; i <= 2 * n; i++)
        head[i] = -1;*/
    memset(head,-1, (2* n + 5 ) * sizeof(int)  );
}
void addedge(int x,int y)
{
    pra[e].to = y;
    pra[e].next = head[x];
    head[x] = e++;
}

long long getpower(long long x, long long n)
{
    long long res = 1LL;
    while (n > 0){
        if (n & 1) res = (res * x) % MOD;
        x = (x*x) % MOD;
        n >>= 1;
    }
    return res%MOD;
}

long long fac[SIZE_N],ff[SIZE_N],f[SIZE_N];

long long c[SIZE_N];//孩子个数
long long cc[SIZE_N];//子树阶乘的乘积
void dfs(int now, int fa)
{
    c[now] = 1LL;
    //vis[now] = 1;

    ff[now] = 1LL;
    cc[now] = 1LL;


    f[now] = 1LL;
    for (int i = head[now]; i != -1; i = pra[i].next){
        int u = pra[i].to;
        if (u != fa){ //&& vis[u] != 1){
            dfs(u,now);
            c[now] += c[u];
            ff[now] = ff[now] * f[u] % MOD;
            cc[now] = cc[now] * fac[c[u] ] % MOD;
        }
    }
    f[now] = (ff[now] * fac[c[now]-1]  )% MOD * getpower(cc[now], MOD-2)% MOD;
}
long long dpf[SIZE_N];
long long ans;
void dfsff(int now, int fa)
{
    //vis[now] = 1;
    long long P = MOD;
    if (now != 1){
        long long t = f[now] * (n-c[now]) %P * cc[now] % P;
        t = getpower(t,MOD-2);
        f[now] = f[fa] * ff[now] % P * fac[c[now]] %P * t % P;
        long long res = f[now] * f[now] %P;
        ans = (ans + res)%P;
    }
    else
        ans = f[now] * f[now] %P;
    for (int i = head[now]; i != -1; i = pra[i].next){
        int u = pra[i].to;
        if (u != fa )//&& vis[u]!= 1)
            dfsff(u,now);
    }
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("input.txt","r",stdin);
#endif
    fac[0] = 1;
    fac[1] = 1;
    for (int i = 2; i <= 1000000; i++)
        fac[i] = ( fac[i-1] * i ) % MOD;
    int T;
    scanf("%d",&T);

    while (T--){
        scanf("%d",&n);init();
        for (int i = 1; i < n; i++){
            int tempx,tempy;
            scanf("%d %d",&tempx,&tempy);
            addedge(tempx,tempy);
            addedge(tempy,tempx);
        }
        dfs(1,0);
        //memset(vis,0,sizeof(vis));
        dfsff(1,0);
        printf("%I64d\n",ans);
    }

    return 0;

}

/*

2
2
1 2
3
1 2
2 3

*/












發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章