SCUT - 482 - 生成树上的点 - Prufer

https://scut.online/p/482

没听说过这个东西。

洛谷也有这个,所以还是要去接触一些奇奇怪怪的知识才行。
https://www.luogu.org/problem/P2290

画了一个表。

1个点:

F[1]=1

2个点:

F[1]=1
F[2]=1

3个点:

F[1]=2/3
F[2]=1/3
F[3]=0

4个点:

F[1]=9/16
F[2]=4/16
F[3]=1/16
F[4]=0

没发现有什么规律,可能是真的要画到5才可以?


Prufer序列,用于对同一形态的无根树映射到序列。用来解决只跟度数有关的树的问题。

1.找度数为1的,且编号最小的点,把它的父亲加入Prufer序列,且把它删除。

然后会得到一个n-2个点的序列,其中出现元素的次数就是他的度数-1。

从Prufer恢复树:

2.取出Prufer的第一个节点x,把不在Prufer里的最小元素y,在x-y之间连边。

性质:

1.prufer序列与无根树一一对应。

2.度数为d_i的节点会在prufer序列中出现d_i-1次。

3.一个n个节点的完全图的生成树个数为n{n-2}。因为对于一个n个点的无根树,它的prufer序列长为n−2,而每个位置有n种可能性,因此可能的prufer序列有n种。很显然每一种无根树唯一对应完全图的一个生成树。

4.对于给定度数序列为d_i的一棵无根树共有 \(\frac{(n-2)!}{\prod_{i=1}^n(d_i-1)!}\) 种情况。由上面的性质可以知道,度数为d_i的节点会在prufer序列中出现d_i-1次。则就是要求出d_i-1个i的全排列个数。而上面那个式子就是可重全排列公式。(即全排列个数除以重复元素内部的全排列个数)


回到这一题,每种生成树对应一个Prufer序列,那么总共肯定是n{n-2}种生成树,其中F[1]肯定是不选1,那么就是(n-1),以此类推。


众所周知,幂函数是完全积性的。把它移动一下就可以了。


还卡内存,真的毒瘤。开多一个F数组拿来复制都不行。
事实上不需要这么强迫症,写个函数映射过去,或者直接在答案里面映射过去就可以了。

试试证明bitset在单个访问的时候对时间的浪费程度比bool大。

然而因为MOD是一个1e9+7,所以不会有任何比它小的数的幂次会MOD它为0,可以直接用G[i]来判断。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int MOD = 1e9 + 7;

int qpow(ll x, int n) {
    ll res = 1;
    while(n) {
        if(n & 1)
            res = res * x % MOD;
        x = x * x % MOD;
        n >>= 1;
    }
    return res;
}

const int MAXN = 5e7 + 500;

int G[MAXN];
int p[3100000], ptop;
//int pk[MAXN]
bool np[MAXN];
int N, L, R;

void sieve(int n) {
    G[0] = 0;
    G[1] = 1;
    //pk[1]=1;
    np[1] = 1;
    for(int i = 2; i <= n; i++) {
        if(!np[i]) {
            p[++ptop] = i;
            //pk[i] = i;
            G[i] = qpow(i, N - 2);
        }
        for(int j = 1, t; j <= ptop && (t = i * p[j]) <= n; j++) {
            np[t] = 1;
            if(i % p[j]) {
                //pk[t] = p[j];
                G[t] = 1ll * G[i] * G[p[j]] % MOD;
            } else {
                //pk[t] = pk[i] * p[j];
                //下面是积性
                /*if(pk[t] == t) {
                    G[t] = qpow(N - t, N - 2);
                } else {
                    G[t] = 1ll * G[pk[t]] * G[t / pk[t]] % MOD;
                }*/
                //其实G[i]是完全积性
                G[t] = 1ll * G[i] * G[p[j]] % MOD;
                break;
            }
        }
    }
    //printf("%d\n",ptop);
    /*for(int i = 1; i <= N; ++i) {
        F[i] = G[N - i];
        //printf("F[%d]=%d\n", i, F[i]);
    }*/
    /*reverse(G, G + N + 1);
    for(int i = 1; i <= N; ++i) {
        G[i] += G[i - 1];
        if(G[i]>=MOD)
            G[i]-=MOD;
        //printf("F[%d]=%d\n", i, F[i]);
    }*/
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    while(~scanf("%d%d%d", &N, &L, &R)) {
        if(N <= 2) {
            printf("%d\n", R - L + 1);
            continue;
        }
        sieve(N);
        int ANS = 0;
        for(int i = N - R; i <= N - L; ++i) {
            ANS += G[i];
            if(ANS >= MOD)
                ANS -= MOD;
        }
        printf("%d\n", 1ll * ANS * qpow(qpow(N, N - 2), MOD - 2) % MOD);
    }
    return 0;
}
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int MOD = 1e9 + 7;

int qpow(ll x, int n) {
    ll res = 1;
    while(n) {
        if(n & 1)
            res = res * x % MOD;
        x = x * x % MOD;
        n >>= 1;
    }
    return res;
}

const int MAXN = 5e7 + 5;

int G[MAXN];
int p[3100000], ptop;
int N, L, R;

void sieve(int n) {
    G[0] = 0;
    G[1] = 1;
    for(int i = 2; i <= n; i++) {
        if(!G[i]) {
            p[++ptop] = i;
            G[i] = qpow(i, N - 2);
        }
        for(int j = 1, t; j <= ptop && (t = i * p[j]) <= n; j++) {
            G[t] = 1ll * G[i] * G[p[j]] % MOD;
            if(!(i % p[j]))
                break;
        }
    }
}

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    while(~scanf("%d%d%d", &N, &L, &R)) {
        if(N <= 2) {
            printf("%d\n", R - L + 1);
            continue;
        }
        sieve(N);
        int ANS = 0;
        for(int i = N - R; i <= N - L; ++i) {
            ANS += G[i];
            if(ANS >= MOD)
                ANS -= MOD;
        }
        printf("%d\n", 1ll * ANS * qpow(qpow(N, N - 2), MOD - 2) % MOD);
    }
    return 0;
}
posted @ 2019-08-13 00:04  韵意  阅读(236)  评论(0编辑  收藏  举报