zoukankan      html  css  js  c++  java
  • [BZOJ2616]SPOJ PERIODNI 树形dp+组合数+逆元

    2616: SPOJ PERIODNI

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 128  Solved: 48
    [Submit][Status][Discuss]

    Description

    Input

    第1行包括两个正整数N,K,表示了棋盘的列数和放的车数。 
    第2行包含N个正整数,表示了棋盘每列的高度。

    Output

    包括一个非负整数,表示有多少种放置的方案,输出答案mod 
    1000000007后的结果即可。 
     

    Sample Input

    5 2
    2 3 1 2 4

    Sample Output

    43

    HINT

    对于100%的数据,有 N≤500,K≤500,h[i] ≤1000000。

    Source

    我们可以先构造笛卡尔树(每次找最低点分为两半)

    之后设f[i][j]表示以i为根的子树共放了j个的方案数。

    每次dp时我们处理g[i]表示左右子树共放了i个的方案数。

    长为n,宽为m的矩阵放k个车的方案数为C(n,k)*A(m,k)

    依据这个每次枚举g[i]转移f即可。

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<cstdlib>
     5 #include<cmath>
     6 #include<algorithm>
     7 #define LL long long
     8 #define mod 1000000007
     9 using namespace std;
    10 LL n,k;
    11 LL g[1005],a[505];
    12 LL f[505][505];
    13 LL p[1000005],inv[1000005];
    14 LL cal(LL x,LL y,LL k){
    15   if(x<k||y<k)return 0;
    16   return p[x]*inv[x-k]%mod*inv[k]%mod*p[y]%mod*inv[y-k]%mod;
    17 }
    18 LL dp(int l,int r,int h) {
    19     if(l>r) return 0;
    20     int lowi=l;
    21     for(int i=l;i<=r;i++) if(a[lowi]>a[i]) lowi=i;
    22     int la=dp(l,lowi-1,a[lowi]),ra=dp(lowi+1,r,a[lowi]);
    23     memset(g,0,sizeof(g));
    24     for(int i=0;i<=lowi-l;i++)
    25         for(int j=0;j<=r-lowi;j++) g[i+j]=(g[i+j]+f[la][i]*f[ra][j])%mod;
    26     for(int i=0;i<=r-l+1;i++)
    27         for(int j=0;j<=i;j++) 
    28             f[lowi][i]=(f[lowi][i]+g[j]*cal(r-l+1-j,a[lowi]-h,i-j))%mod;
    29     return lowi;
    30 }
    31 LL power(LL x,LL ad) {
    32     LL ans=1;
    33     while(ad) {
    34         if(ad&1) ans=ans*x%mod;
    35         x=x*x%mod;
    36         ad>>=1;
    37     }
    38     return ans;
    39 }
    40 int main() {
    41     p[0]=1;
    42     for(int i=1;i<=1000000;i++) p[i]=p[i-1]*i%mod;
    43     inv[1000000]=power(p[1000000],mod-2);
    44     for(int i=1000000-1;i>=0;i--)inv[i]=inv[i+1]*(i+1)%mod;
    45     scanf("%lld%lld",&n,&k);
    46     for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    47     f[0][0]=1;
    48     printf("%lld
    ",f[dp(1,n,0)][k]);
    49 }
    View Code
    O(∩_∩)O~ (*^__^*) 嘻嘻…… O(∩_∩)O哈哈~
  • 相关阅读:
    InnoDB实现MVCC原理
    Python中定义函数时参数有默认值的小陷阱
    Python系统编程笔记
    Python中的字典
    Python中常见的字符串小笔试题
    Oracle常见名词解析
    Oracle数据库面试题【转载】
    Oracle日期语言修改
    Oracle日期时间函数大全
    Oracle数据库分页的三种方法
  • 原文地址:https://www.cnblogs.com/wls001/p/8074636.html
Copyright © 2011-2022 走看看