• Luogu4547 [THUWC2017]随机二分图


    Description

    link

    Solution

    题目本质上要求的是 (n!) 种完备匹配乘上各自出现的概率乘上 (2^n) 之和

    状态定义为 (f_{S,T}) 为左部点的集合为 (S),右部点的集合为 (T) 的权值和

    转移考虑枚举一条边

    [f_{S,T}=f_{S xor st,T xor ed} imes v_{st,ed} ]

    固定枚举边的顺序可以进行转移,考虑到 (bitcount(S)=bitcount(T)) 和数据范围,考虑记忆化搜索更为可行

    同时还要注意的是要从按照二进制位从小到大进行转移,比较

    (这里新学到了,原来只会递推的)

    最后来的瓶颈就是 (v_{st,ed})

    第一种边是比较好做的,直接是 (frac 1 2)

    第二种边第三种边就不太好做

    发现这里的式子只支持第一种边这种类别的,那么就考虑用期望线性性来拆边

    先把两个边都用 (v=frac 1 2) 插入

    然后考虑差异

    第二类边需要再插入两边并集 (v=frac 1 4),第三类边需要再插入两边并集且 $v=-frac 14 $

    (后面的就是考虑共同出现的情况)

    Code

    #include<bits/stdc++.h>
    using namespace std;
    #define reg register
    #define For(i,a,b) for(reg int i=a;i<=b;++i) 
    #define Down(i,a,b) for(reg int i=b;i>=a;--i) 
    namespace yspm{
        inline int read()
        {
            int res=0,f=1; char k;
            while(!isdigit(k=getchar())) if(k=='-') f=-1;
            while(isdigit(k)) res=res*10+k-'0',k=getchar();
            return res*f;
        }
        inline int p(int x){return (1<<(x-1));}
        const int N=1e5+10,mod=1e9+7;
        struct edge{
            int st,ed;
            long long val;
        }e[N];
        #define ll long long
        map<int,ll> f[N];
        int inv2=5e8+4,inv4=25e7+2,cnt,n,m;
        inline ll calc(int S,int T)
        {
            if(!S) return 1;
            if(f[S].count(T)) return f[S][T];
            For(i,1,cnt)
            {
                ll s=e[i].st,t=e[i].ed,v=e[i].val;
                if((S|s)!=S||(T|t)!=T||S>=(s<<1)) continue;
                f[S][T]=(f[S][T]+calc(S^s,T^t)*v%mod)%mod;
            }
            return f[S][T];
        }
        signed main()
        {
            n=read(); m=read(); 
            For(i,1,m)
            {
                int opt=read();
                if(opt)
                {
                    int x1=read(),x2=read(),x3=read(),x4=read();
                    e[++cnt]=(edge){p(x1),p(x2),inv2};
                    e[++cnt]=(edge){p(x3),p(x4),inv2};
                    if(x1==x3||x2==x4) continue;
                    if(opt==1) e[++cnt]=(edge){p(x1)|p(x3),p(x2)|p(x4),inv4};
                    else e[++cnt]=(edge){p(x1)|p(x3),p(x2)|p(x4),mod-inv4};
                }
                else 
                {   
                    e[++cnt].st=p(read());
                    e[cnt].ed=p(read());
                    e[cnt].val=inv2;
                }
            }
            printf("%lld
    ",(1<<n)*calc((1<<n)-1,(1<<n)-1)%mod);
            return 0;
        }
    }
    signed main(){return yspm::main();}
    

    (有待卡常……)

    Review

    (1.) 记忆话搜索完成各类 (dp) 的方法(尤其是空间开不下的情况)

    (2.) 期望线性性!!!!!(其实感觉自己不是很会用这个东西,找题目练练吧)

    (3.) 固定从小到大依次转移的方法

  • 相关阅读:
    数组定义和使用
    跳转语句—break,continue,goto
    案例 天线抬不起头来
    int是几位;short是几位;long是几位 负数怎么表示
    Python3的类注意事项
    用usb线配置直流电机驱动器不能配置成功
    案例 电源灯亮,但是就是不闪灯,而且也下载不了程序
    关于ai算法的一个点子
    进程 并发 线程 032
    ftp功能深度剖析 + 线程 031
  • 原文地址:https://www.cnblogs.com/yspm/p/13620667.html
Copyright © 2020-2023  润新知