zoukankan      html  css  js  c++  java
  • Luogu4547 THUWC2017 随机二分图 概率、状压DP

    传送门


    考虑如果只有$0$组边要怎么做。因为$N leq 15$,考虑状压$DP$。设$f_i$表示当前的匹配情况为$i$时的概率($i$中$2^0$到$2^{N-1}$表示左半边的匹配情况,$2^N$到$2^{2N-1}$表示右半边的匹配情况),转移就是随便取一条边将其起终边对应的位置去掉然后乘上$0.5$。

    然而会发现这会重复转移,也就是说先选择$a$再选择$b$与先选择$b$再选择$a$在计算中被算作了两种情况,但实际上只能够算作一种。我们考虑固定$DP$的顺序。我们每一次选择$lowbit(i)$对应的点进行转移,这样转移就是左部分的点从小到大连边,转移也就不会重复了。

    接着我们考虑$1$组边和$2$组边。首先我们考虑将这两组边中的两条边拆开考虑,这样会有:只选择第一条边参与贡献概率为$50\%$,只选择第二条边参与贡献概率为$50\%$,两条边同时参与贡献概率为$25\%$。发现只有两条边同时参与贡献时的概率是有问题的,所以我们考虑加上一条边。这一条边对应这一组的两条边,对于$1$组边给予其$25\%$的概率,对于$2$组边给予其$-25\%$的概率,这样概率就是对的了。这一条边要在较小的那一个左端点计算的时候进行计算。

    上面那个不是很好理解,慢慢思考一下qwq

    最后,$2^{30}$的数组是不可能开下的,考虑到有很多冗余状态,使用记忆化搜索就可以通过这道题了。

      1 #include<bits/stdc++.h>
      2 #define ld long double
      3 //This code is written by Itst
      4 using namespace std;
      5 
      6 inline int read(){
      7     int a = 0;
      8     bool f = 0;
      9     char c = getchar();
     10     while(c != EOF && !isdigit(c)){
     11         if(c == '-')
     12             f = 1;
     13         c = getchar();
     14     }
     15     while(c != EOF && isdigit(c)){
     16         a = (a << 3) + (a << 1) + (c ^ '0');
     17         c = getchar();
     18     }
     19     return f ? -a : a;
     20 }
     21 
     22 const int MAXN = 15 * 15;
     23 const int MOD = 1e9 + 7;
     24 struct Edge{
     25     int start , end , belStart , belEnd;
     26     long long p;
     27 }now[MAXN * 3];
     28 int range[17] , num2[270000] , poww2[31] , N , cnt , inv2 , inv4;
     29 map < int , int > dp;
     30 
     31 inline void add(int x , int y , int belx , int bely , int p){
     32     now[++cnt].start = x;
     33     now[cnt].end = y;
     34     now[cnt].belStart = belx;
     35     now[cnt].belEnd = bely;
     36     now[cnt].p = p;
     37 }
     38 
     39 bool operator <(Edge a , Edge b){
     40     return a.start < b.start;
     41 }
     42 
     43 int dfs(int dir){
     44     if(dp.count(dir))
     45         return dp[dir];
     46     if(!dir)
     47         return 1;
     48     int t = num2[dir & -dir] , sum = 0;
     49     for(int i = range[t] ; i < range[t + 1] ; ++i)
     50         if(dir & poww2[now[i].end])
     51             if(now[i].belStart == -1)
     52                 sum = (sum + dfs(dir ^ poww2[t] ^ poww2[now[i].end]) * now[i].p) % MOD;
     53             else
     54                 if((dir & poww2[now[i].belStart]) && (dir & poww2[now[i].belEnd]))
     55                     sum = (sum + dfs(dir ^ poww2[t] ^ poww2[now[i].end] ^ poww2[now[i].belStart] ^ poww2[now[i].belEnd]) * now[i].p) % MOD;
     56     return dp[dir] = sum;
     57 }
     58 
     59 inline int poww(long long a , int b){
     60     int times = 1;
     61     while(b){
     62         if(b & 1)
     63             times = times * a % MOD;
     64         a = a * a % MOD;
     65         b >>= 1;
     66     }
     67     return times;
     68 }
     69 
     70 int main(){
     71 #ifndef ONLINE_JUDGE
     72     freopen("4547.in" , "r" , stdin);
     73     //freopen("4547.out" , "w" , stdout);
     74 #endif
     75     N = read();
     76     for(int i = 0 ; i < N ; ++i)
     77         num2[1 << i] = i;
     78     poww2[0] = 1;
     79     for(int i = 1 ; i < (N << 1) ; ++i)
     80         poww2[i] = poww2[i - 1] << 1;
     81     inv2 = poww(2 , MOD - 2);
     82     inv4 = poww(4 , MOD - 2);
     83     for(int M = read() ; M ; --M){
     84         int t = read() , x = read() - 1 , y = read() + N - 1;
     85         add(x , y , -1 , -1 , inv2);
     86         if(t){
     87             int belx = read() - 1 , bely = read() + N - 1;
     88             add(belx , bely , -1 , -1 , inv2);
     89             if(belx < x){
     90                 swap(x , belx);
     91                 swap(y , bely);
     92             }
     93             if(belx != x && bely != y)
     94                 add(x , y , belx , bely , t == 1 ? inv4 : MOD - inv4);
     95         }
     96     }
     97     sort(now + 1 , now + cnt + 1);
     98     for(int i = 1 ; i <= cnt ; ++i)
     99         if(!range[now[i].start])
    100             range[now[i].start] = i;
    101     range[N] = cnt + 1;
    102     printf("%lld
    " , 1ll * dfs((1 << (N << 1)) - 1) * poww(2 , N) % MOD);
    103     return 0;
    104 }
  • 相关阅读:
    HDU1814 Peaceful Commission
    POJ1679 The Unique MST
    POJ 3243 Clever Y
    POJ 3463 Sightseeing
    POJ1274 The Perfect Stall
    POJ 2417 Discrete Logging
    POJ1011 Sticks
    前端面试资源整理(一)
    小程序和腾讯地图联合使用
    快速创建 HTML5 Canvas 电信网络拓扑图
  • 原文地址:https://www.cnblogs.com/Itst/p/10052767.html
Copyright © 2011-2022 走看看