zoukankan      html  css  js  c++  java
  • CF995F Cowmpany Cowmpensation

    题目链接:http://codeforces.com/contest/995/problem/F

    题目大意:

      给定一棵 (n) 个节点的有根树(根为 (1) 号结点),为这棵树上的每一个结点赋值(赋值的范围为 ([1,D])),要求父结点的值不小于子结点值,问有多少种赋值方案。

      (1 le n le 3000, 1 le D le 10^9)

    知识点:  树形DP、拉格朗日插值法

    解题思路:

      可以证明:对于一棵有 (n) 个结点的树,其答案是一个关于 (D) 的 (n) 次多项式 (f(D))。(虽然并不知道怎么证明......)

      那么我们只需要用树形 (DP) 求出前 (n+1) 项:(f(0), f(1), f(2), ... f(n)),然后用拉格朗日插值法求出 (f(D)) 即可。

    AC代码:

      1 #include <bits/stdc++.h>
      2 
      3 using namespace std;
      4 typedef long long LL;
      5 const int MAXN=3005;
      6 const LL MOD = 1e9 + 7;
      7 
      8 
      9 LL powmod(LL x, LL y) {
     10     LL res = 1;
     11     x %= MOD;
     12     while (y) {
     13         if (y & 1)    res = res*x%MOD;
     14         y >>= 1;
     15         x = x*x%MOD;
     16     }
     17     return res;
     18 }
     19 namespace Polysum {
     20     //拉格朗日插值法对多项式求和
     21     const int D = 3010;
     22     //    LL a[D];  自改,待议
     23     LL f[D], g[D], p[D], p1[D], p2[D], b[D], h[D][2], C[D];
     24 
     25     LL calcn(int d, LL *a, LL n) {
     26         if (n <= d)        return a[n];
     27         p1[0] = p2[0] = 1;
     28         for (int i = 0; i <= d; i++) {
     29             LL t = (n - i + MOD) % MOD;
     30             p1[i + 1] = p1[i] * t%MOD;
     31         }
     32         for (int i = 0; i <= d; i++) {
     33             LL t = (n - d + i + MOD) % MOD;
     34             p2[i + 1] = p2[i] * t%MOD;
     35         }
     36         LL ans = 0;
     37         for (int i = 0; i <= d; i++) {
     38             LL t = g[i] * g[d - i] % MOD*p1[i] % MOD*p2[d - i] % MOD*a[i] % MOD;
     39             if ((d - i) & 1)        ans = (ans - t + MOD) % MOD;
     40             else
     41                 ans = (ans + t) % MOD;
     42         }
     43         return ans;
     44     }
     45     void init(int M) {
     46         f[0] = f[1] = g[0] = g[1] = 1;
     47         for (int i = 2; i < M + 5; i++)
     48             f[i] = f[i - 1] * i%MOD;
     49         g[M + 4] = powmod(f[M + 4], MOD - 2);
     50         for (int i = M + 3; i >= 1;i--)
     51             g[i] = g[i + 1] * (i + 1) % MOD;
     52     }
     53     //对于给定的 x+1 个点,对应于它们的次数不超过 x 的拉格朗日多项式只有一个
     54     //因此,如果我们要求和的多项式的最高项是 m-1,那么我们就要输入其前 m 个点
     55     LL polysum(LL n, LL *a, int m) {
     56         //输入 a[] 的前 m 项:a[1], a[2], ..., a[m]
     57         //输出 a[] 的前 n 项之和: sum_{i=0}^{n-1} a[i]
     58         //    LL b[D];  自改,待议
     59         for (int i = 0; i <= m; i++)    b[i] = a[i];
     60         b[m + 1] = calcn(m, b, m + 1);
     61         for (int i = 1; i < m + 2; i++)
     62             b[i] = (b[i - 1] + b[i]) % MOD;
     63         return calcn(m + 1, b, n - 1);
     64     }
     65     LL qpolysum(LL R, LL n, LL *a, int m) {
     66         //输入 a[] 的前 m+1 项:a[1], a[2], ..., a[m]
     67         //输出 a[x]*R^x 的前 n 项之和:sum_{i=0}^{n-1} a[i]*R^i
     68         if (R == 1)    return polysum(n, a, m);
     69         a[m + 1] = calcn(m, a, m + 1);
     70         LL r = powmod(R, MOD - 2);
     71         LL p3 = 0, p4 = 0, c, ans;
     72         h[0][0] = 0, h[0][1] = 1;
     73         for (int i = 1; i < m + 2;i++){
     74             h[i][0] = (h[i - 1][0] + a[i - 1])*r%MOD;
     75             h[i][1] = h[i - 1][1] * r%MOD;
     76         }
     77         for (int i = 0; i < m + 2; i++) {
     78             LL t = g[i] * g[m + 1 - i] % MOD;
     79             if (i & 1) p3 = ((p3 - h[i][0] * t) % MOD + MOD) % MOD, p4 = ((p4 - h[i][1] * t) % MOD + MOD) % MOD;
     80             else p3 = (p3 + h[i][0] * t) % MOD, p4 = (p4 + h[i][1] * t) % MOD;
     81         }
     82         c = powmod(p4, MOD - 2)*(MOD - p3) % MOD;
     83         for (int i = 0; i < m + 2; i++)
     84             h[i][0] = (h[i][0] + h[i][1] * c) % MOD;
     85         for (int i = 0; i < m + 2; i++)
     86             C[i] = h[i][0];
     87         ans = (calcn(m, C, n)*powmod(R, n) - c) % MOD;
     88         if (ans < 0)    ans += MOD;
     89         return ans;
     90     }
     91 }
     92 
     93 vector<int> G[MAXN];
     94 LL dp[MAXN][MAXN],pre[MAXN][MAXN];
     95 int n;
     96 void dfs(int rt){
     97     bool flag=false;
     98     for(int i=0;i<G[rt].size();i++){
     99         int v=G[rt][i];
    100         dfs(v);
    101         flag=true;
    102     }
    103     for(int j=1;j<=n;j++)   dp[rt][j]=1;
    104     if(flag){
    105         for(int i=0;i<G[rt].size();i++){
    106             int v=G[rt][i];
    107             for(int j=1;j<=n;j++){
    108                 dp[rt][j]=dp[rt][j]*pre[v][j]%MOD;
    109             }
    110         }
    111     }
    112     pre[rt][1]=dp[rt][1];
    113     for(int j=2;j<=n;j++)
    114         pre[rt][j]=(pre[rt][j-1]+dp[rt][j])%MOD;
    115 }
    116 int main(){
    117     LL D;
    118     scanf("%d%lld",&n,&D);
    119     for(int i=2;i<=n;i++){
    120         int t;
    121         scanf("%d",&t);
    122         G[t].push_back(i);
    123     }
    124     dfs(1);
    125     Polysum::init(MAXN);
    126     printf("%lld
    ",Polysum::calcn(n,pre[1],D));
    127 
    128     return 0;
    129 }
    “这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”
  • 相关阅读:
    2014年去哪儿网笔试题--一个10*10的矩阵(可以理解为棋盘),随时生成一组数据填入矩阵,任何一个位置的数字除4进行计算,按余数着色...
    2014年去哪儿网笔试题--给定一个整型数组,对这个整型素组排序,使得按序拼接数组各元素得到的值最小。
    剑指Offer:面试题25
    字符串模式匹配KMP算法
    堆排序算法原理
    HashMap和HashTable 学习
    JAVA的IO学习
    输出图片的php代码前面不能有空白行
    PHP中最容易忘记的一些知识点总结
    PHP中cookie与session总结
  • 原文地址:https://www.cnblogs.com/Blogggggg/p/9357301.html
Copyright © 2011-2022 走看看