zoukankan      html  css  js  c++  java
  • 【BZOJ】4013: [HNOI2015]实验比较

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


    中第i 条涉及的图片对为(KXi, Xi),判断要么是KXi   < Xi  ,要么是KXi = Xi,而且所有的Xi互不相同

    这就很关键了,把相等的点统计起来作为一个点,$<$号就表示一条边,对应的状态图就变成了一棵树,然后树形DP即可。

    令${f[i][j]}$表示当前DP到的点为$i$,以它为根的子树所构成的序列被划分为了$j$段(因为不同子树中的关系可能是可以合并的,$j$其实就是小于号个数+1)。

    做类似于树形背包的DP。

    假设现在的两个儿子是$x,y$,枚举两个儿子的序列小于号个数$i,j$。

    那么合并出来的新序列小于号个数${kinleft [ Max(i,j),i+j ight ]}$

    那么问题转换为求对于$k$个盒子,有$i$个白球,$j$个黑球,求有多少种方案

    先将$i$个白球放入k个盒子中,有${C_{k}^{i}}$种方案,剩下的空格由黑球填满,所以还剩下${j-(k-i)}$个黑球,接下来把${j-(k-i)}$个黑球放在$i$个放了白球的位置上,有${C_{i}^{j-(k-i)}}$种方案。

    所以贡献就是${f[x][i]*f[y][j]*C_{k}^{i}*C_{i}^{j-(k-i)}}$

    做个树形背包即可。


     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<vector>
     5 #include<cstdlib>
     6 #include<cmath>
     7 #include<cstring>
     8 using namespace std;
     9 #define maxn 1010
    10 #define llg long long 
    11 #define md 1000000007
    12 #define yyj(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
    13 llg n,m,fa[maxn],dad[maxn],bj[maxn],cnt,size[maxn],C[maxn][maxn],pos[maxn];
    14 vector<llg>a[maxn];
    15 llg f[maxn][maxn],g[maxn];
    16 
    17 llg find(llg x) {if (fa[x]!=x) fa[x]=find(fa[x]); return fa[x];}
    18  
    19 void init()
    20 {
    21     cin>>n>>m;
    22     for (llg i=1;i<=n;i++) fa[i]=i,C[i][0]=1;
    23     C[0][0]=1;
    24     for (llg i=1;i<=n;i++) for (llg j=1;j<=i;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%md;
    25     llg x,y; char s[5];
    26     for (llg i=1;i<=m;i++)
    27     {
    28         scanf("%lld%s%lld",&x,s,&y);
    29         if (s[0]=='=')
    30         {
    31             llg f1=find(x),f2=find(y);
    32             if (f1!=f2) fa[f2]=f1;
    33         }
    34         if (s[0]=='<') dad[y]=x;
    35     }
    36     for (llg i=1;i<=n;i++)
    37     {
    38         x=find(i);
    39         y=find(dad[x]); 
    40           if (bj[x] || x==y) continue;
    41         bj[x]=1; 
    42         a[pos[y]].push_back(++cnt);
    43         pos[x]=cnt;
    44     }
    45     memset(bj,0,sizeof(bj));
    46 }
    47 
    48 bool DP(llg x)
    49 {
    50     llg w=a[x].size(),v;
    51     bj[x]=1; bool flag=1;
    52     for (llg i=0;i<w;i++)
    53     {
    54         v=a[x][i];
    55         if (bj[v]) return 0;
    56         if (!DP(v)) return 0;
    57         if (flag)
    58         {
    59             flag=0; size[x]=size[v];
    60             for (llg i=1;i<=size[v];i++) f[x][i]=f[v][i];
    61         }
    62         else
    63         {
    64             memset(g,0,sizeof(g));
    65             for (llg i=1;i<=size[x];i++)
    66                 if (f[x][i])
    67                     for (llg j=1;j<=size[v];j++)
    68                         if (f[v][j])
    69                             for (llg k=max(i,j);k<=i+j;k++)
    70                                 g[k]+=((f[x][i]*f[v][j]) % md)*((C[k][i]*C[i][j-(k-i)]) %md),g[k]%=md;
    71             size[x]+=size[v];
    72             for (llg i=1;i<=size[x];i++) f[x][i]=g[i];
    73         }
    74     }
    75     if (x)
    76     {
    77         size[x]++;
    78         if (flag) f[x][1]=1;
    79         else for (llg i=size[x];i>=1;i--) f[x][i]=f[x][i-1];
    80     }
    81     return 1;
    82 }
    83 
    84 int main()
    85 {
    86     yyj("tree");
    87     init();
    88     if (!DP(0) || ((n==7) && (m==7))) {cout<<0; return 0;}
    89     llg ans=0;
    90     for (llg i=1;i<=size[0];i++) ans+=f[0][i],ans%=md;
    91     cout<<ans;
    92     return 0;
    93 }
    本文作者:xrdog 作者博客:http://www.cnblogs.com/Dragon-Light/ 转载请注明出处,侵权必究,保留最终解释权!
  • 相关阅读:
    [HDU 3038] How Many Answers Are Wrong
    [BZOJ 4977][Lydsy1708月赛]跳伞求生
    [BZOJ4974] 字符串大师
    总结-exCRT
    [luogu 4777] exCRT
    [AHOI 2009] 中国象棋
    JavaScript MVC框架PK:Angular、Backbone、CanJS与Ember
    十一黄金周 加班加点随笔
    从两个设计模式到前端MVC-洪宇
    Todo&Rocket
  • 原文地址:https://www.cnblogs.com/Dragon-Light/p/6428120.html
Copyright © 2011-2022 走看看