• BZOJ5006 THUWC2017随机二分图(概率期望+状压dp)


      下称0类为单边,1类为互生边,2类为互斥边。对于一种匹配方案,考虑其出现的概率*2n后对答案的贡献,初始为1,如果有互斥边显然变为0,否则每有一对互生边其贡献*2。于是有一个显然的dp,即设f[S1][S2]为左边选取S1右边选取S2对答案的贡献。转移时考虑S1中编号最小的点x与右边的点y匹配。首先将f[S1-(1<<x)][S2-(1<<y)]统计进去。然后若(x,y)是单边,或者虽存在互生互斥关系,但其对应边的左端点还不在S1中或就是x,或右端点还不在S2中或就是y,就不管了;否则若互斥将f[S1-(1<<x)-(1<<x')][S2-(1<<y)-(1<<y')]减掉,若互生将f[S1-(1<<x)-(1<<x')][S2-(1<<y)-(1<<y')]加上,其中(x',y')是(x,y)的对应边。这样大概就是C(30,15)*15的。

      但是这只有暴力20分,甚至连空间都开不下。然而满分做法和他是一个复杂度的。对上面的做法改为记忆化搜索,map存储状态就可以了。多了log也多了80分。不是非常理解意义何在。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<map>
    using namespace std;
    #define ll long long
    #define N 15
    #define P 1000000007
    char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    int n,m,typ[N][N],match[N][N][2],s[1<<N];
    map<int,int> f;
    void inc(int &x,int y){x+=y;if (x>=P) x-=P;}
    inline int trans(int n,int m){return n<<N|m;}
    int solve(int i,int j)
    {
        if (f.find(trans(i,j))!=f.end()) return f[trans(i,j)];
        int x=i&-i,ans=0;
        for (int t=j,k=t&-t;t;t^=k,k=t&-t)
        if ((k&j)&&typ[s[x]][s[k]]>=0)
        {
            inc(ans,solve(i^x,j^k));
            int u=match[s[x]][s[k]][0],v=match[s[x]][s[k]][1];
            if ((u&i)&&(v&j)&&x!=u&&k!=v)
            {
                if (typ[s[x]][s[k]]==1) inc(ans,solve(i^x^u,j^k^v));
                if (typ[s[x]][s[k]]==2) inc(ans,P-solve(i^x^u,j^k^v));
            }
        }
        f[trans(i,j)]=ans;return ans;
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj5006.in","r",stdin);
        freopen("bzoj5006.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read(),m=read();
        memset(typ,255,sizeof(typ));
        for (int i=1;i<=m;i++)
        {
            int op=read(),x=read()-1,y=read()-1;
            if (op==0) typ[x][y]=0;
            else
            {
                int p=read()-1,q=read()-1;
                typ[x][y]=typ[p][q]=op;
                match[x][y][0]=1<<p,match[x][y][1]=1<<q;
                match[p][q][0]=1<<x,match[p][q][1]=1<<y;
            }
        }
        for (int i=0;i<n;i++) s[1<<i]=i;
        f[0]=1;
        cout<<solve((1<<n)-1,(1<<n)-1);
        return 0;
    }
  • 相关阅读:
    MongoDB zip 包安装注意事项及过程
    20个免费的React Admin仪表板模板
    React常用的5个UI框架
    create-react-app my-app出错
    查看Vue,React等框架的排名以及编程语言的排名
    flex流动布局中的单个子元素位置如何自定义
    小程序跳转页面后,动态刷新跳转页面
    table表格动态合并
    Windows 10 提权漏洞复现及武器化利用
    ISO:Fedora/Centos-6/7-LiveCD 利用iso文件 本地硬盘安装:方式1:Grub4Dos partnew模拟
  • 原文地址:https://www.cnblogs.com/Gloid/p/10085209.html
Copyright © 2020-2023  润新知