【题解】毒蛇越狱(FWT+容斥)

【题解】毒蛇越狱(FWT+容斥)

问了一下大家咋做也没听懂,按兵不动没去看题解,虽然已经晓得复杂度了....最后感觉也不难

用FWT_OR和FWT_AND做一半分别求出超集和和子集和,然后

  • 枚举问号是01,裸的,\(O(2^{cnt[?]})\)
  • 默认问号是1,利用子集和求,\(O(2^{cnt[1]})\)
  • 默认问号是0,利用超集和求,\(O(2^{cnt[0]})\)

可以知道\(min(cnt)\le n/3\),所以复杂度\(O(n2^n 2^{n/3}Q)\)

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;  typedef long long ll;
inline int qr(){
    int ret=0,f=0,c=getchar();
    while(!isdigit(c)) f|=c==45,c=getchar();
    while( isdigit(c)) ret=ret*10+c-48,c=getchar();
    return f?-ret:ret;
}
const int maxn=1<<20|1;
char s[maxn];
int data[maxn],c[maxn],s0[maxn],s1[maxn],n,q;
int cnt[3];

inline void FWT_AND(int*a,const int&len,const int&tag){
    for(int t=1;t<len;t<<=1)
        for(int i=0;i<len;i+=t<<1)
            for(int k=0;k<t;++k)
                a[i+k]+=a[t+i+k]*tag;
}

inline void FWT_OR(int*a,const int&len,const int&tag){
    for(int t=1;t<len;t<<=1)
        for(int i=0;i<len;i+=t<<1)
            for(int k=0;k<t;++k)
                a[t+i+k]+=a[i+k]*tag;
}

int num[maxn],u;
int main(){
    n=qr(); q=qr();
    u=(1<<n)-1;
    scanf("%s",s);
    for(int t=1;t<1<<n;++t) num[t]=num[t^(t&-t)]+1;
    for(int t=0;t<1<<n;++t) data[t]=s[t]-48,s0[t]=data[t],s1[t]=data[t];
    FWT_AND(s0,1<<n,1); FWT_OR(s1,1<<n,1);
    while(q--){
        if(scanf("%s",s)==EOF) return 0;
        memset(cnt,0,sizeof cnt);
        for(int t=0;t<n;++t){
            if(isdigit(s[t])) c[t]=s[t]==49;
            else c[t]=2;
            ++cnt[c[t]];
        }
        int base=0,wen=0,ans=0,k=min({cnt[0],cnt[1],cnt[2]});
        for(int t=0;t<n;++t)
            if(c[t]<=1) base=base<<1|c[t],wen<<=1;
            else wen=wen<<1|1,base<<=1;
        if(cnt[2]==k){
            for(int t=wen;~t;--t>=0?t&=wen:t)
                ans+=data[t|base];
        }else if(cnt[1]==k){
            for(int t=base;~t;--t>=0?t&=base:t){
                int g=t|wen;
                if(num[base^t]&1) ans-=s1[g];
                else ans+=s1[g];
            }
        }else{
            base^=u; base^=wen;
            for(int t=base;~t;--t>=0?t&=base:t){
                int g=t|wen;
                if(num[base^t]&1) ans-=s0[g^u];
                else ans+=s0[g^u];
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/winlere/p/11979938.html

时间: 2024-10-31 19:22:57

【题解】毒蛇越狱(FWT+容斥)的相关文章

【题解】Gnutella Chessmaster(容斥+下降幂+二项式定理)

[题解]Gnutella Chessmaster(容斥+下降幂+二项式定理) Gnutella Chessmaster 绝世好题! 题目大意:有一个\(n\times n\)的棋盘,现在要在上面放\(k\)个Bishop,每个Bishop打两条对角线,问你放Bishop的方案数,方案不同当且仅当一个位置上存在主教的状态不同.你要对于每个k输出方案. prop1 对于这个棋盘二分图染色((1,1)=白),显然白色格子上面的Bishop打不到黑色格子上面的Bishop,于是我们可以分开算黑白格子的方

poj2773 Happy 2006(二分+容斥)

题目链接:点这里!!!! 题意: 给你两个整数m(1<=m<=1e6),k(1<=k<=1e8).求第k个与m互质的数是多少. 题解: 直接二分+容斥. 代码: #include<cstdio> #include<cstring> #include<iostream> #include<sstream> #include<algorithm> #include<vector> #include<bitse

【洛谷U20626】gemo 容斥 FWT 高斯消元

题目大意 给你一个无向图,有\(m\)个询问,每次给你一个点\(x\)和一个点集\(S\),问你从\(x\)开始走,每次从一个点随机的走到与这个点相邻的点,问你访问\(S\)中每个点至少一次的期望步数是多少. \(n\leq 18,m\leq 100000\) 题解 有个东西叫min-max容斥: \[ \max(S)=\sum_{T\subseteq S}{(-1)}^{|T|+1}\min(T) \] 这道题中,\(\min(S)\)是从点\(x\)开始走,走到\(S\)中任意一个点的期望步

【题解】分特产(组合数+容斥)

[题解]分特产(组合数+容斥) 一道小水题. 假如没有这个要求每个人都要有一个特产的限制我们直接可以组合数. 我们又发现人(本质上)是没有区别的,所以容斥的复杂度只有\(O(n)\) \(n\)个人分\(m\)个特产,每个特产有\(a_i\)个,人可以不拿特产,的方案数就是把\(a_i\)分成\(n\)份,而且可以分为\(0\)份. 这个的答案就是 \[ f(n)=\prod_{i=1}^m {a_i+n-1\choose n-1} \] 意思就是有\(a_i+n\)个球分成不为空\(n\)份的

[HAOI2015]按位或——Min-Max容斥+FWT

题面 Bzoj4036 解析 考虑$ans=E(max(t[i])), i\in S, S=\begin{Bmatrix} 1,2,\cdots, n\end{Bmatrix}$,这里$t[i]$表示第$i$位变成$1$的时间,$E(max(t[i]))$表示最后变成$1$的一位的期望时间,暂时记为$E(max(S))$,注意这个不等于$max(E(S))$ 然后套上$Min-Max$容斥,$ans=\sum_{T \subseteq S}E(min(T))$,$E(min(T))$表示$T$中

HDU 4135 Co-prime(容斥:二进制解法)题解

题意:给出[a,b]区间内与n互质的个数 思路:如果n比较小,我们可以用欧拉函数解决,但是n有1e9.要求区间内互质,我们可以先求前缀内互质个数,即[1,b]内与n互质,求互质,可以转化为求不互质,也就是有除1的公因数.那么我们把n质因数分解,就能算出含某些公因数的不互质的个数.因为会重复,所以容斥解决.因为因数个数可能很多(随便算了一个20!> 2e18,所以质因数分解个数不会超过20个),我们可以用二进制来遍历解决. #include<set> #include<map>

HDU 2841 Visible Trees(容斥)题解

题意:有一块(1,1)到(m,n)的地,从(0,0)看能看到几块(如果两块地到看的地方三点一线,后面的地都看不到). 思路:一开始是想不到容斥...后来发现被遮住的地都有一个特点,若(a,b)有gcd(a,b)!= 1,那么就会被遮住.因为斜率k一样,后面的点会被遮住,如果有gcd,那么除一下就会变成gcd = 1的那个点的斜率了.所以问题转化为求gcd不为1有几个点,固定一个点,然后容斥. #include<set> #include<map> #include<queue

题解报告:hdu 4135 Co-prime(容斥定理入门)

Problem Description Given a number N, you are asked to count the number of integers between A and B inclusive which are relatively prime to N.Two integers are said to be co-prime or relatively prime if they have no common positive divisors other than

FJUT3565 最大公约数之和(容斥)题解

题意:给n,m,求出 思路:题意为求出1~m所有数和n的gcd之和.显然gcd为n的因数.我们都知道gcd(a,b)= c,那么gcd(a/c,b/c)= 1.也就是说我们枚举n所有的因数k,然后去找1~m/k中和n/k互质的个数就是gcd为k的个数.这个直接容斥就行. 代码: #include<iostream> #include<algorithm> #include<cstdio> #include<stdio.h> #include<strin