码迷,mamicode.com
首页 > 其他好文 > 详细

「THUWC 2017」随机二分图

时间:2018-12-27 20:21:40      阅读:167      评论:0      收藏:0      [点我收藏+]

标签:怎样   for   mat   har   mod   复杂度   pre   表示   dig   

「THUWC 2017」随机二分图

解题思路 :

首先有一个 \(40pts\) 的做法:

\(20pts\) 暴力枚举最终的匹配是怎样的,check一下计算方案数,后 \(20pts\)\(f[s][i]\) 表示当前左边的点匹配到前 \(i\) 个,右边的点匹配状况是 \(s\) 时继续往下匹配方案数的期望,枚举与 \(i\) 相连的边转移即可。

对于剩下的 \(t=1,t=2\) 的情况,先和 \(t = 0\) 一样直接连 \((a1,b1), (a2,b2)\)。然后观察此时概率发生的偏差。

\(t=1\) 为例,只选 \((a1,b1)\) 或者只选 \((a2, b2)\) 时概率和正确情况一样都是 \(\frac{1}{2}\) 。但是如果两条边都选此时算的概率是 \(\frac{1}{4}\) ,而应该是 \(\frac{1}{2}\) ,所以还要补连一种转移同时选上四个点概率是 \(\frac{1}{4}\) ,根据期望的线性性,正确性显然。

对于 \(t=2\) 情况,和上面一样分析,发现对于同时选的情况多算了 \(\frac{1}{4}\) ,补连一条概率是 \(-\frac{1}{4}\) 的转移即可。

此时我们就不能按照 \(40pts\) 的方法DP了,需要设 \(f[s1][s2]\) 表示此时左边点匹配状况是 \(s1\),右边匹配状况是 \(s2\) ,继续向下匹配方案数的期望。但是为了不重,我们每次还是要为 \(s1\) 中编号最小为匹配的点安排匹配,那么这样状态数就是和 \(40pts\) 的转移同阶的,用一个map记忆化一下复杂度就是 \(O(n^22^n)\)

code

/*program by mangoyang*/
#pragma GCC optimize("Ofast", "inline")
#include<bits/stdc++.h>
#define inf ((int)(1e9))
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
    int f = 0, ch = 0; x = 0;
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
    for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
    if(f) x = -x;
}
const int INV2 = 500000004, INV4 = 250000002, mod = 1e9 + 7;
map<int, int> f;
int a[300], b[300], n, m, cnt;

inline int Pow(int a, int b){
    int ans = 1;
    for(; b; b >>= 1, a = 1ll * a * a % mod)
        if(b & 1) ans = 1ll * ans * a % mod;
    return ans;
}

inline int dfs(int mask){
    if(mask == (1 << (n << 1)) - 1) return 1;
    if(f.count(mask)) return f[mask];
    int now = 0, tmp = 0;
    for(int i = n - 1; ~i; i--)
        if(!((1 << i) & mask)) now = (1 << i);
    for(int i = 1; i <= cnt; i++)
        if((now & a[i]) && !(mask & a[i]))
            (tmp += 1ll * dfs(mask | a[i]) * b[i] % mod) %= mod;
    return f[mask] = tmp;
}

int main(){
    read(n), read(m);
    for(int i = 1, op, x, y; i <= m; i++){
        read(op), read(x), read(y), x--, y--;
        int tmp = (1 << x) | (1 << y + n);
        a[++cnt] = tmp, b[cnt] = INV2;
        if(op){
            read(x), read(y), x--, y--;
            a[++cnt] = (1 << x) | (1 << y + n), b[cnt] = INV2;
            if(tmp & ((1 << x) | (1 << y + n))) continue;
            tmp |= (1 << x) | (1 << y + n);
            a[++cnt] = tmp, b[cnt] = op == 1 ? INV4 : -INV4 + mod;
        }
    }
    cout << 1ll * dfs(0) * Pow(2, n) % mod << endl;
    return 0;
}

「THUWC 2017」随机二分图

标签:怎样   for   mat   har   mod   复杂度   pre   表示   dig   

原文地址:https://www.cnblogs.com/mangoyang/p/10186853.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!