• 【LOJ】#2351. 「JOI 2017/2018 决赛」毒蛇越狱


    题解

    没啥特别好的算法,是个讨论题,由于0 1 ?三类数位中最少的不会超过6
    如果1不超过6,那么记录(f1(S))
    (sum_{T subset S} val(T))这个可以通过类似FMT的递推式在(L 2^L)求出
    然后容斥,如果这个数和1的个数差别是偶数就加上否则就减掉

    如果0不超过6,记录(f0(S))
    (sum_{T supset S} val(T))
    然后容斥,如果这个数有偶数个1就加上否则减掉

    问号很少的话就是直接枚举计算值了

    复杂度(O(2^{lfloor frac{L}{3} floor}Q))

    代码

    #include <iostream>
    #include <cstdio>
    #include <vector>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <map>
    //#define ivorysi
    #define pb push_back
    #define space putchar(' ')
    #define enter putchar('
    ')
    #define mp make_pair
    #define pb push_back
    #define fi first
    #define se second
    #define mo 974711
    #define MAXN 2000005
    #define eps 1e-3
    #define RG register
    #define calc(x) __builtin_popcount(x)
    using namespace std;
    typedef long long int64;
    typedef double db;
    template<class T>
    void read(T &res) {
        res = 0;char c = getchar();T f = 1;
        while(c < '0' || c > '9') {
    	if(c == '-') f = -1;
    	c = getchar();
        }
        while(c >= '0' && c <= '9') {
    	res = res * 10 + c - '0';
    	c = getchar();
        }
        res *= f;
    }
    template<class T>
    void out(T x) {
        if(x < 0) {putchar('-');x = -x;}
        if(x >= 10) {
    	out(x / 10);
        }
        putchar('0' + x % 10);
    }
    int L,Q,f0[MAXN],f1[MAXN];
    char s[MAXN],str[25];
    void Solve() {
        read(L);read(Q);
        scanf("%s",s);
        for(int i = 0 ; i < 1 << L ; ++i) f0[i] = f1[i] = s[i] - '0';
        for(int i = 1 ; i < (1 << L) ; i <<= 1) {
    	for(int j = 0 ; j < (1 << L) ; ++j) {
    	    if(j & i) f1[j] += f1[j ^ i],f0[j ^ i] += f0[j];
    	}
        }
        for(int i = 1 ; i <= Q ; ++i) {
    	scanf("%s",str);
    	int x = 0,y = 0,z = 0,ans = 0;
    	for(int j = L - 1 ; j >= 0 ; --j) {
    	    if(str[j] == '1') x |= (1 << (L - 1 - j));
    	    else if(str[j] == '0') y |= (1 << (L - 1 - j));
    	    else z |= (1 << (L - 1 - j));
    	}
    	if(calc(x) <= 6) {
    	    for(int S = x ; ; S = (S - 1) & x) {
    		if(calc(S ^ x) & 1) ans -= f1[S | z];
    		else ans += f1[S | z];
    		if(!S) break;
    	    }
    	}
    	else if(calc(y) <= 6) {
    	    for(int S = y ; ; S = (S - 1) & y) {
    		if(calc(S) & 1) ans -= f0[S | x];
    		else ans += f0[S | x];
    		if(!S) break;
    	    }
    	}
    	else {
    	    for(int S = z ; ; S = (S - 1) & z) {
    		ans += s[S | x] - '0';
    		if(!S) break;
    	    }
    	}
    	out(ans);enter;
        }
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Solve();
        return 0;
    }
    
  • 相关阅读:
    文章块引用模版
    悬停工具提示
    各个知识点
    Github Fork 缎带.html
    css重置样式
    暗灰色的圆形按钮.html
    css中的居中的方法
    display:table的几个用法 块级子元素垂直居中
    <meta>标签中http-equiv属性的属性值X-UA-Compatible详解
    jQuery难学是因为什么?
  • 原文地址:https://www.cnblogs.com/ivorysi/p/9144676.html
Copyright © 2020-2023  润新知