• bzoj 3812 主旋律


    这题好难啊 为什么dp都这么难 计数问题  好像完全不会啊

    这是wc2015 陈老师讲的题

    我们可以先考虑把这个点集拆成多个强连通分量 如果强连通分量的数量大于2 那么这一个生成子图对答案是没有贡献的

    对于两个强连通分量从 拆出来的那一个 向其他的连边 是不会把两个强连通分量缩在一起的

    考虑容斥?? 复杂度貌似有点高 要枚举每一个强连通分量

    极强无比的做法::

    1. f[S]表示点集S的生成子图强联通的方案数 
    2. g[S]表示点集S的生成子图G中,若G的所有联通块都强联通,则G对g[S]存在一个贡献 
    3. 如果G中有奇数个连通块,则对g[S]的贡献为+1,否则为-1 
    4. h[S]表示点集S的诱导子图中有多少条边 
    5.  
    6. f[S]=2^h[S]-Σ[T是S的非空子集]2^cnt*g[T] 
    7. 其中cnt=|{x->y|x∈S,y∈S-T}|  
    8. (注意此时的g[S]不包含整个S强联通的情况) 

    lef 即S-T

    h[i^j]+w[j] 即cnt

    (f[i]+=mod-pows[h[i^j]+w[j]]*g[j]%mod)%=mod;

      for(int j=lef;j;(--j)&=lef)
        (g[i]+=mod-f[i^j]*g[j]%mod)%=mod;

    核心代码以给出

    可是我总觉得这一类dp题 再出来我好像还是不太会做 开始怀疑做dp题看题解的意义

     1 #include <bits/stdc++.h>
     2 #define breaks printf("!")
     3 #define ll long long
     4 #define mod 1000000007
     5 using namespace std;
     6 
     7 int n,m,num[1<<8];
     8 int cd[1<<15],rd[1<<15];
     9 ll f[1<<15],g[1<<15],h[1<<15],pows[16*16];
    10 inline Counts(int x){return num[x>>8]+num[x&255];}
    11 int main()
    12 {
    13     scanf("%d%d",&n,&m);
    14     for(int i=1;i<(1<<8);i++)
    15         num[i]=num[i>>1]+(i&1);
    16     pows[0]=1;for(int i=1;i<=m;i++) pows[i]=(pows[i-1]<<1)%mod;
    17     for(int i=1;i<=m;i++)
    18     {
    19         int x,y; scanf("%d%d",&x,&y);
    20         cd[1<<(x-1)]|=1<<(y-1); rd[1<<(y-1)]|=1<<(x-1);
    21     }
    22     //for(int i=1;i<=m;i++) printf("%d ",num[i]); printf("
    ");
    23     for(int i=1;i<1<<n;i++)
    24     {
    25         int one=i&-i,lef=i^one;
    26         h[i]=h[lef]+Counts(rd[one]&lef)+Counts(cd[one]&lef);
    27         for(int j=lef;j;(--j)&=lef)
    28             (g[i]+=mod-f[i^j]*g[j]%mod)%=mod;
    29         static int w[1<<15];
    30         f[i]=pows[h[i]];
    31         //breaks;
    32         for(int j=i;j;(--j)&=i)
    33         {
    34             if(j==i) w[j]=0;
    35             else 
    36             {
    37                 int tmp=(i^j)&-(i^j);
    38                 w[j]=w[j^tmp]-Counts((i^j)&rd[tmp])+Counts(j&cd[tmp]);
    39             }
    40             (f[i]+=mod-pows[h[i^j]+w[j]]*g[j]%mod)%=mod;
    41         }
    42         g[i]+=f[i]; g[i]%=mod;
    43     }
    44     printf("%lld
    ",f[(1<<n)-1]);
    45     return 0;
    46 }
  • 相关阅读:
    Go并发
    frida打印class的信息--java反射
    Go嵌入类型
    Go方法集-应该传值类型还是指针类型?
    springboot使用unidbg遇到logback和sl4j依赖冲突,正确配置文件
    Eureka 微服务注册发现开源框架
    呼吸机CPAP与APAP:哪个更好?
    如何看睡眠监测报告
    抓包工具 tcpdump 用法说明
    利用ROS的samba功能实现centos定期备份ROS配置
  • 原文地址:https://www.cnblogs.com/wcz112/p/6351393.html
Copyright © 2020-2023  润新知