zoukankan      html  css  js  c++  java
  • LOJ #2540. 「PKUWC 2018」随机算法(概率dp)

    题意

    LOJ #2540. 「PKUWC 2018」随机算法

    题解

    朴素的就是 (O(n3^n)) dp 写了一下有 (50pts) ... 大概就是每个点有三个状态 , 考虑了但不在独立集中 , 考虑了并且在独立集中 , 还没考虑 . 转移就很显然了 qwq

    然后要优化嘛 , 把其中两个状态合起来 , 也就是分成考虑了和没考虑了的两种 .

    其中考虑了的那种 , 只会存在两种状态 , 要么是在独立集内 , 要么就是与独立集联通 , 没有考虑的 绝对不和独立集联通 就行了 .

    然后我们枚举一个集合 , 考虑强制把一个点选进来 . 如果要选它 , 那么它周围的一圈都不能去选 .

    为了使这个 dp 不存在后效性 , 我们不能让之后的选的点连得点存在于独立集中 , 我们把他周围一圈的都放进来就行了 .

    也就是说当前维护的集合 , 会被最外面没有存在于独立集中的一圈给包围住 .

    然后连上来的时候会有很多种排列的方式 , 直接乘上一个排列数就行了 . (相当于预留位置)

    最后算答案因为是概率 , 除以 (frac{1}{n!}) 就行了 .

    这些我都是问 DOFY 才懂的 , 还是太菜啦 ~

    具体来说 方程是这样的 ((displaystyle f_{i,s}) 当前选了 (i) 个点 , 考虑过的集合是 (s) , 与 (k) 相邻的所有点(包括它自己)的集合为 (w_k) ):

    [[k otin s] ~ displaystyle f_{i,s} imes A_{n-|s|-1}^{|w_k-w_k cap s|} o f_{i+1,s cup w_k} ]

    时间复杂度是 (O(n^2 2^n)) 可以通过此题了 .

    然后进行一波优化 , 对于一个确定的考虑过的集合 (s) 那么它选取最大独立集 , 是选取全局的最大独立集的必要条件 .

    (这个应该显然吧 ... 因为最外圈你不要的话 , 如果里面不是最大独立集的话 , 外面取得最大也达不到全局最大)

    那么第一位考虑选点的就可以不要了 , 时间复杂度就是 (O(n2^n)) .

    这样写了一下 莫名奇妙就是 LOJ 最快的了 ?

    代码

    #include <bits/stdc++.h>
    #define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
    #define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
    #define Set(a, v) memset(a, v, sizeof(a))
    using namespace std;
    
    inline bool chkmin(int &a, int b) {return b < a ? a = b, 1 : 0;}
    inline bool chkmax(int &a, int b) {return b > a ? a = b, 1 : 0;}
    
    inline int read() {
        int x = 0, fh = 1; char ch = getchar();
        for (; !isdigit(ch); ch = getchar()) if (ch == '-') fh = -1;
        for (; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + (ch ^ 48);
        return x * fh;
    }
    
    void File() {
    #ifdef zjp_shadow
    	freopen ("2540.in", "r", stdin);
    	freopen ("2540.out", "w", stdout);
    #endif
    }
    
    const int N = 20;
    int n, m, Con[N];
    
    typedef long long ll;
    const int Mod = 998244353;
    
    ll fpm(ll x, int power) {
    	ll inv = 1;
    	for (; power; power >>= 1, (x *= x) %= Mod)
    		if (power & 1) (inv *= x) %= Mod;
    	return inv;
    }
    
    ll fac[N + 5], ifac[N + 5];
    void Init(int maxn) {
    	fac[0] = ifac[0] = 1;
    	For (i, 1, maxn) fac[i] = fac[i - 1] * i % Mod;
    	ifac[maxn] = fpm(fac[maxn], Mod - 2);
    	Fordown (i, maxn - 1, 1) ifac[i] = ifac[i + 1] * (i + 1) % Mod;
    }
    
    int dp[1 << N], bit[1 << N], MaxSize[1 << N];;
    
    inline int A(int n, int m) { if (m > n || n < 0 || m < 0) return 0; return fac[n] * ifac[n - m] % Mod; }
    
    int main () {
    	File();
    
    	n = read(); m = read(); Init(n); 
    	For (i, 1, m) {
    		int u = read() - 1, v = read() - 1;
    		Con[u] |= (1 << v);
    		Con[v] |= (1 << u);
    	}
    
    	For (i, 0, n - 1) Con[i] |= (1 << i);
    
    	dp[0] = 1;
    	int maxsta = (1 << n) - 1;
    	For (i, 0, maxsta) bit[i] = bit[i >> 1] + (i & 1);
    
    	For (i, 0, maxsta) if (dp[i]) {
    		For (j, 0, n - 1) if (!((1 << j) & i)) {
    			register int Next = i | Con[j];
    			if (chkmax(MaxSize[Next], MaxSize[i] + 1)) dp[Next] = 0;
    			if (MaxSize[Next] == MaxSize[i] + 1) (dp[Next] += 1ll * dp[i] * A(n - bit[i] - 1, bit[Con[j] ^ (Con[j] & i)] - 1) % Mod) %= Mod;
    		}
    	}
    
    	printf ("%lld
    ", 1ll * dp[maxsta] * ifac[n] % Mod);
        return 0;
    }
    
  • 相关阅读:
    浅拷贝与深拷贝
    Hibernate入门(1)-第一个Hibernate程序
    Spring入门(10)-Spring JDBC
    【Java,IDEA】创建自己的代码模版快速生成
    【Java,IDEA】使用IDEA自动生成序列化ID
    【Project】原生JavaWeb工程 02 登陆业务的流程(第一阶段样例)
    【AJAX】Asynchronous JavaScript And XML (非同步的JS & XML)
    【JS】06 语法补充
    【JS】05 DOM 文档对象模型 P2 元素的CRUD、Dom集合对象
    【JS】04 DOM 文档对象模型 P1 查找元素、改变内容、绑定事件
  • 原文地址:https://www.cnblogs.com/zjp-shadow/p/9096357.html
Copyright © 2011-2022 走看看