zoukankan      html  css  js  c++  java
  • bzoj4036 [HAOI2015]按位或 状压DP + MinMax 容斥

    题目传送门

    https://lydsy.com/JudgeOnline/problem.php?id=4036

    题解

    变成 (2^n-1) 的意思显然就是每一个数位都出现了。

    那么通过 MinMax 容斥,可以把问题转化为对于一个集合 (S),求 (S) 中至少有一个元素出现的概率。

    这个问题等价于求 (S) 中没有任何一个元素出现的概率,即出现的数都是 (S) 的补集的子集的概率。

    这个问可以通过 SoSDP 实现,时间复杂度 (O(n2^n))


    关于 SoSDP

    这个东西可以 (O(n2^n)) 求出一个序列中是 (S) 的子集的集合的权值和。

    (f[i][S]) 表示 (S) 中只有 (i) 以下的位上的 (1) 变成 (0) 的“子集”的权值和。

    于是如果 (i in S),那么 (f[i][S] = f[i - 1][S] + f[i - 1][S - {i}])

    否则 (f[i][S] = f[i - 1][S])

    最后 (f[n][S]) 就是 (S) 的子集的答案。可以使用一维滚动数组优化,


    这道题的代码:

    #include<bits/stdc++.h>
    
    #define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
    #define dbg(...) fprintf(stderr, __VA_ARGS__)
    #define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
    #define fi first
    #define se second
    #define pb push_back
    
    template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b, 1 : 0;}
    template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b, 1 : 0;}
    
    typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
    
    template<typename I> inline void read(I &x) {
    	int f = 0, c;
    	while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
    	x = c & 15;
    	while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
    	f ? x = -x : 0;
    }
    
    #define lowbit(x) ((x) & -(x))
    
    const int N = 20 + 7;
    const int M = (1 << 20) + 7;
    
    int n, S;
    double f[M];
    int p[M];
    
    inline void work() {
    	for (int i = 0; i < n; ++i)
    		for (int s = 1; s <= S; ++s)
    			if ((s >> i) & 1) f[s] += f[s ^ (1 << i)];
    	for (int i = 1; i <= S; ++i) if (f[S] == f[S ^ i]) {
    		puts("INF");
    		return;
    	}
    	for (int s = 1; s <= S; ++s) p[s] = p[s ^ lowbit(s)] + 1;
    	double ans = 0;
    	for (int s = 1; s <= S; ++s)
    		if (p[s] & 1) ans += 1 / (1 - f[S ^ s]);
    		else ans -= 1 / (1 - f[S ^ s]);
    	printf("%.10lf
    ", ans);
    }
    
    inline void init() {
    	read(n);
    	S = (1 << n) - 1;
    	for (int i = 0; i <= S; ++i) scanf("%lf", &f[i]);
    }
    
    int main() {
    #ifdef hzhkk
    	freopen("hkk.in", "r", stdin);
    #endif
    	init();
    	work();
    	fclose(stdin), fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    OO助教总结
    OO2019第四单元作业总结
    OO2019第三单元作业总结
    OO2019第二单元作业
    OO2019第一单元作业总结
    OO第一单元作业总结
    BUAA_OO_2020_Unit4_Summary
    BUAA_OO_2020_Unit3_Summary
    BUAA_OO_2020_Uint2_Summary
    闫金柱-OO第一单元总结
  • 原文地址:https://www.cnblogs.com/hankeke/p/bzoj4036.html
Copyright © 2011-2022 走看看