Nowcoder 智乃酱的子集与超集 (高维前缀和)

智乃酱的子集与超集

Sol:

高维前缀和

从二维前缀和的另一种方法扩展的高维。

普通的二维前缀和需要容斥。另一种方法是先处理行的前缀和,再处理列的前缀和,算两次,不需要容斥。

高位前缀和同样运用了这个原理。

储存一下代码当板子。

Code:

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dep(i,a,b) for(int i=(a);i>=(b);--i)
#define lowbit(x) (x&(-x))
#define debug(x) cout<<#x<<" :"<<x<<endl
#define debug1(x) cout<<#x<<" :"<<x<<" "
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int N=2e5+20;
const int MAX=10000007;
inline int read() {
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0',c=getchar();}
    return x*f;
}

inline void out(int x) {   
    if(x>9) out(x/10);   
    putchar(x%10+'0'); 
}     
int q[N];
const int M = 2000000;
ll pre[M];
ll suf[M];
int n,m;
int main(){
    scanf("%d %d",&n,&m);
    for(int i=0;i<n;++i){
        scanf("%d",&q[i]);
    }
    for(int i=0;i<(1<<n);++i){
        ll sum=0;
        for(int j=0;j<n;++j){
            if((i)&(1<<j)){
                sum^=q[j];
            }
        }
        pre[i]=suf[i]=sum;
    }

    for(int i=0;i<n;++i){
        for(int j=0;j<(1<<n);++j){
            if(j&(1<<i)){
                pre[j]+=pre[j^(1<<i)];
            }
            else suf[j]+=suf[j^(1<<i)];
        }
    }

    for(int i=1;i<=m;++i){
        int cnt;
        int x;
        scanf("%d",&cnt);
        int st=0;
        for(int j=1;j<=cnt;++j){
            scanf("%d",&x);
            st|=(1<<(x-1));
        }
        printf("%lld %lld\n",pre[st],suf[st]);

    }
    return 0;
}             

上一篇:2021.7.4 nowcoder错题本


下一篇:【nowcoder 15167D】 WA:贪心