uva 1436 - Counting heaps(计数)

题目链接:uva 1436 - Counting heaps

题目大意:给出一个树的形状,现在为这棵树标号,保证根节点的标号值比子节点的标号值大,问有多少种标号树。

解题思路:和村名排队的思路是一只的uva11174,最后问题只和树德结构有直接关系,f(root)=(s(root)?1)!(s(1)?s(2)???s(n)

但是给定的取模数不是质数,所以不能用逆元做,只能将分子分母分别拆分成质因子,然后对质因子进制约分。因为最后的答案一定是正整数,所以对于每个质因子,分子分解出的因子个数一定大于等于分母分解出的,最后约分肯定剩下的是分子,再用快速幂求解。

剪枝,因为分解质因子的次数非常多,所以需要对分解函数剪枝,当u是质数时,可以直接终止返回。

#include <cstdio>
#include <cstring>
#include <queue>

using namespace std;

const int N = 500005;
typedef long long ll;

int P = 0, prime[N], ispri[N];
int n, f[N], vis[N], cnt[N];
ll mod;

void getPrime (int N) {
    memset(ispri, 0, sizeof(ispri));
    for (int i = 2; i < N; i++) {
        if (ispri[i])
            continue;

        prime[P++] = i;
        for (int j = 2 * i; j < N; j += i)
            ispri[j] = 1;
    }
}

void getNode () {
    memset(cnt, 0, sizeof(cnt));

    queue<int> que;
    for (int i = 1; i <= n; i++)
        if (vis[i] == 0)
            que.push(i);

    while (!que.empty()) {
        int u = que.front();
        que.pop();

        cnt[u]++;

        int v = f[u];
        cnt[v] += cnt[u];
        vis[v]--;

        if (vis[v] == 0)
            que.push(v);
    }
}

void init () {
    memset(vis, 0, sizeof(vis));
    scanf("%d%lld", &n, &mod);

    f[1] = 0;
    for (int i = 2; i <= n; i++) {
        scanf("%d", &f[i]);
        vis[f[i]]++;
    }
    getNode();

    memset(vis, 0, sizeof(vis));
    for (int i = 1; i <= n; i++)
        vis[cnt[i]]++;
}

ll power (ll x, ll m) {
    ll ans = 1;
    while (m) {
        if (m&1)
            ans = ans * x % mod;

        x = x * x % mod;
        m /= 2;
    }
    return ans;
}

void cal (int u, int v) {
    for (int i = 0; i < P; i++) {
        int k = prime[i];

        while (u % k == 0) {
            cnt[k] += v;
            u /= k;
        }

        if (ispri[u] == 0) {
            cnt[u] += v;
            return;
        }
    }
}

ll solve () {
    memset(cnt, 0, sizeof(cnt));

    for (int i = 2; i <= n; i++)
        cal(i, 1);

    for (int i = 2; i <= n; i++)
        if (vis[i])
            cal(i, -vis[i]);

    ll ans = 1;
    for (int i = 0; i < P; i++) {
        ll u = prime[i];
        if (cnt[u])
            ans = (ans * power(u, cnt[u])) % mod;
    }
    return ans;
}

int main () {
    getPrime(N);

    int cas;
    scanf("%d", &cas);
    while (cas--) {
        init();
        printf("%lld\n", solve());
    }
    return 0;
}

uva 1436 - Counting heaps(计数)

时间: 2024-10-24 08:31:43

uva 1436 - Counting heaps(计数)的相关文章

UVA 1436 - Counting heaps(计数问题)

UVA 1436 - Counting heaps 题目链接 题意:给定一个树的结构,放1-n数字进去,父亲结点值必须小于子节点,问情况有几种. 思路:f[u]表示以u为子树的情况,那么子树情况为f(v1), f(v2), f(v3)... f(vn).去组成子树相当于从中选s(v1), s(v2), s(v3) ... s(vn).根据组合数学,情况为f(v1) f(v2) ... f(vn) (s(u) - 1)! \ (s(v1)! s(v2)! ... * s(vn)!)化简后得到公式:

UVA - 1436 Counting heaps

Description We are given a rooted tree of n vertices. The vertices are to be labeled with numbers 1, 2,..., n so that each label is unique and the heap condition holds, i.e. the label of any vertex is less than the label of its parent. How many such

UVA 10574 - Counting Rectangles 计数

Given n points on the XY plane, count how many regular rectangles are formed. A rectangle is regular if and only if its sides are all parallel to the axis.InputThe ?rst line contains the number of tests t (1 ≤ t ≤ 10). Each case contains a single lin

UVA 12075 - Counting Triangles(容斥原理计数)

题目链接:12075 - Counting Triangles 题意:求n * m矩形内,最多能组成几个三角形 这题和UVA 1393类似,把总情况扣去三点共线情况,那么问题转化为求三点共线的情况,对于两点,求他们的gcd - 1,得到的就是他们之间有多少个点,那么情况数就可以求了,然后还是利用容斥原理去计数,然后累加出答案 代码: #include <stdio.h> #include <string.h> #include <algorithm> using nam

UVA 10574 - Counting Rectangles(枚举+计数)

10574 - Counting Rectangles 题目链接 题意:给定一些点,求能够成几个矩形 思路:先把点按x排序,再按y排序,然后用O(n^2)的方法找出每条垂直x轴的边,保存这些边两点的y坐标y1, y2.之后把这些边按y1排序,再按y2排序,用O(n)的方法找出有几个连续的y1, y2都相等,那么这些边两两是能构成矩形的,为C2cnt种,然后累加起来就是答案 代码: #include <stdio.h> #include <string.h> #include <

UVA - 12075 Counting Triangles

Description Triangles are polygons with three sides and strictly positive area. Lattice triangles are the triangles all whose vertexes have integer coordinates. In this problem you have to find the number of lattice triangles in anMxN grid. For examp

uva 1510 - Neon Sign(计数)

题目链接:uva 1510 - Neon Sign 题目大意:给定n个点,任意三点不共线,并且两两点之间有一条线,给定线的颜色.问说有多少个三角形三边同色. 解题思路:对于每个点,记录该点黑色边的数量和红色边的数量,考虑以该点为顶点的三角形,从红色边中选一条,黑色边中选一条,组成的三角形一定是不满足的.因为一个不同色三角形会有两个点满则,所以考虑了两次.用总的个数减掉不同色的即可. #include <cstdio> #include <cstring> #include <

uva 294 - Divisors(枚举+计数)

题目连接:uva 294 - Divisors 题目大意:给出一个范围L~U,问说在该范围中因子数最多的数是多少. 解题思路:枚举L~U中的数,将数分解成质因子,利用乘法原理求总因子数. #include <cstdio> #include <cstring> #include <cmath> int countFactor (int x) { int ans = 1; int m = sqrt(x+0.5); for (int i = 2; i <= m; i+

counting sort 计数排序

//counting sort 计数排序 //参考算法导论8.2节 #include<cstdio> #include<cstring> #include<algorithm> #include<cassert> using namespace std; const int k=5; const int n=7; int a[n]={5, 5, 1, 2 , 5, 4, 1}; int b[n]; int c[k+1]; int main() { int m