• 【BZOJ 1005】[HNOI2008]明明的烦恼(暴力化简法)


    【题目链接】:http://www.lydsy.com/JudgeOnline/problem.php?id=1005

    【题意】

    中文题

    【题解】

    一棵节点上标有序号的树会和一个prufer数列唯一对应;
    这个prufer数列可以这样获得;
    每次找到序号最小的叶子节点;
    然后把它删掉;
    将与之相连的那个点加入数列的尾端;
    重复上述操作直到只剩下两个节点为止;
    即最后
    一棵n个节点的树对应了一个长度为n-2的数列;
    eg:
    这里写图片描述
    比如说这个图;
    最小叶节点为2,删除2,将3计入序列
    最小叶节点为4,删除4,将5计入序列
    最小叶节点为5,删除5,将1计入序列
    最小叶节点为1,删除1,将3计入序列
    图中只剩下两个节点,退出
    于是得到这棵树的Prufer序列为{3,5,1,3}
    容易发现;
    序列中某个数字出现的次数,就是它的度数-1;
    且一个prufer序列(有序数列)也唯一对应了一棵树;
    假设题目所给的n个节点,那些d[i]!=-1的每个节点的所需度数减去1后的总和为tot;
    设有特定度数的节点个数为y,然后令没有特殊需要的节点个数为m
    这样,我们相当于在n-2个空格当中选择tot个位置去放那些需要的y个节点;
    那就是个组合问题了;
    先在n-2个空格中选tot个位置;
    即C(n-2,tot);······①
    然后对于第i个节点,他要在位置里面选d[i]-1个空格放进去;

    C(tot,d[i]-1]);·····②
    然后对于第i+1个节点;
    C(tot-(d[i]-1),d[i+1]-1);····③

    然后将①②③….全部乘起来就是有特殊需求的节点的答案了;
    至于剩下的m个没有特殊需求的节点;
    在剩余的n-2-tot个位置里面;每个位置都有m个选择;
    即m^(n-2-tot);
    也乘上去就好;
    最后全部乘在一起;
    化简后就变为
    【m^(n-2-tot)* (n-2)!】/【(n-2-tot)!* (d[1]-1)!*(d[2]-1)!……(d[n]-1)!】;
    因为是方案,所以最后肯定可以约成整数;
    所以问题就变成将n!质因数分解了;
    (1..n每个数都质因数分解一下);
    可以考虑分母和分子对最后结果的质因数分解形式的贡献;
    分子的质因子对最后结果的相应质因子的指数的贡献是+1的;
    而分母的质因子对最后结果的相应质因子的指数的贡献肯定是-1的;
    有几个就减去相应的次数或加上相应的次数就好;
    (需要写高精度);
    (下一篇有更好的化简方法);

    【完整代码】

    /**************************************************************
        Problem: 1005
        User: chengchunyang
        Language: C++
        Result: Accepted
        Time:36 ms
        Memory:1304 kb
    ****************************************************************/
    
    #include <bits/stdc++.h>
    using namespace std;
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define LL long long
    #define rep1(i,a,b) for (int i = a;i <= b;i++)
    #define rep2(i,a,b) for (int i = a;i >= b;i--)
    #define mp make_pair
    #define pb push_back
    #define fi first
    #define se second
    #define rei(x) scanf("%d",&x)
    #define rel(x) scanf("%I64d",&x)
    
    typedef pair<int,int> pii;
    typedef pair<LL,LL> pll;
    
    const int dx[9] = {0,1,-1,0,0,-1,-1,1,1};
    const int dy[9] = {0,0,0,-1,1,-1,1,-1,1};
    const double pi = acos(-1.0);
    const int N = 1100;
    
    int n,d[N],m,tot,cnt[N];
    int ans[N],len = 1;
    
    void go(int t,int x)
    {
        for (int i = 2;i*i<=t;i++)
            while (t%i==0)
            {
                cnt[i]+=x;
                t/=i;
            }
        cnt[t]+=x;
    }
    
    void cheng(int p)
    {
        int x = 0;
        rep1(i,1,len)
        {
            ans[i] = ans[i]*p+x;
            x = ans[i]/10;
            ans[i]%=10;
        }
        while (x>0)
        {
            ans[++len] = x;
            x = ans[len]/10;
            ans[len]%=10;
        }
    }
    
    int main()
    {
        //freopen("F:\rush.txt","r",stdin);
        rei(n);
        rep1(i,1,n)
        {
            rei(d[i]);
            if (d[i]==0) return puts("0"),0;
            if (d[i]==-1)
                m++;
            else
                d[i]--,tot+=d[i];
        }
        if (n-2<tot)
            return puts("0"),0;
        rep1(i,1,n-2)
            go(i,1);
        rep1(i,1,n-2-tot)
            go(i,-1);
        rep1(i,1,n)
            rep1(j,1,d[i])
                go(j,-1);
        ans[1] = 1;
        rep1(i,2,n)
            rep1(j,1,cnt[i])
                cheng(i);
        rep1(i,1,n-2-tot)
            cheng(m);
        rep2(i,len,1)
            printf("%d",ans[i]);
        return 0;
    }
  • 相关阅读:
    洛谷 1736 创意吃鱼法
    有多重限制的背包
    洛谷 1417 烹调方案
    2008 noip 传纸条
    环形石子合并 洛谷 1880 && hdu 3506 Monkey Party
    洛谷 1282 多米诺骨牌
    (金明的预算方案)依赖性的背包
    分组背包问题
    混合背包问题
    多重背包问题
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7626625.html
Copyright © 2020-2023  润新知