Luogu4547 [THUWC2017]随机二分图

Description

link

Solution

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

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

转移考虑枚举一条边

\[f_{S,T}=f_{S\ xor\ st,T \ xor\ ed}\times 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\n",(1<<n)*calc((1<<n)-1,(1<<n)-1)%mod);
        return 0;
    }
}
signed main(){return yspm::main();}

(有待卡常……)

Review

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

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

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

上一篇:1097E. Egor and an RPG game(Dilworth定理)


下一篇:Android set与get/全局变量