「THUWC 2017」随机二分图

题目

https://loj.ac/problem/2290

思路

先考虑n!怎么做
若组0、1、2有恰好一条边在这个匹配,则概率∗1/2
若组1有恰好两条边,则概率∗1/2
若组2有恰好两条边,则概率∗0
设一个f[S1][S2]表示左边选了S1,右边选了S2的概率和。
需要确立一个转移顺序,也就是每次转移必须使S1的最低的0变成1.
状态数不是很多

代码

#include<bits/stdc++.h>
#define mod 1000000007
#define Inv2 500000004
#define Inv4 250000002
using namespace std;
template <typename T>
void read(T &s) {
    s = 0;
    char ch = getchar();
    while (!isdigit(ch)) ch = getchar();
    while (isdigit(ch)) s = ((s + (s << 2)) << 1) + ch - '0',ch = getchar();
}
int n,m,tl,tw[32];
map<int,int> f;
int Fast_Power(int u,int k) {
    int Sum = 1;
    while (k) {
        if(k & 1)
            Sum = 1ll * u * Sum % mod;
        u = 1ll * u * u % mod,k >>= 1;
    }
    return Sum;
}
struct Line {
    int Sta,val;
} t[510];
int DFS(int w) {
    if(w == tw[2 * n] - 1)
        return 1;
    if(f.count(w))
        return f[w];
    //	cout << w << " ";
    int now = 0,Tmp = 0;
    for(int i = 0; i < n; ++i)
        if(!(tw[i] & w))
            now = tw[i];
    for(int i = 1; i <= tl; ++i)
        if((now & t[i].Sta) && !(t[i].Sta & w))
            Tmp = (Tmp + 1ll * DFS(w | t[i].Sta) * t[i].val) % mod;
    return f[w] = Tmp;
}
int main() {
    read(n),read(m),tw[0] = 1;
    for(int i = 1; i <= 2 * n; ++i) tw[i] = tw[i - 1] << 1;
    for(int i = 1,opt,x,y,Tmp; i <= m; ++i) {
        read(opt),read(x),read(y),x--,y--;
        Tmp = tw[x] + tw[y + n],t[++tl].Sta = Tmp,t[tl].val = Inv2;
        if(opt) {
            read(x),read(y),x--,y--,t[++tl].Sta = tw[x] + tw[y + n],t[tl].val = Inv2;
            if(Tmp & (tw[x] | tw[y + n]))
                continue;
            Tmp |= tw[x] | tw[y + n];
            t[++tl].Sta = Tmp;
            if(opt == 2)
                t[tl].val = -Inv4 + mod;
            else
                t[tl].val = Inv4;
        }
    }
    printf("%lld\n",1ll * DFS(0) * Fast_Power(2,n) % mod);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值