高維前綴和
學了一發高維前綴和。
一般我們求多維前綴和是用容斥的,但是當維度很高時會很煩,這時就要用另一種求前綴和的方法。
打個比方,假設我們要求二維前綴和:
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
a[i][j]+=a[i][j-1];
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
a[i][j]+=a[i-1][j];
這樣就很好寫了。而高維前綴和可以解決關於子集和超集統計的問題(複雜度爲,而枚舉子集的複雜度爲),只要把每一位看作一維進行操作就好了。
對於這道題,當時,取反後是的超集,反之亦然。那麼只需要做一遍高維前綴和就可以求出任意一個超集了。
代碼:
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1000005
#define F inline
using namespace std;
int n,a[N],s[1<<22];
F char readc(){
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
return l==r?EOF:*l++;
}
F int _read(){
int x=0; char ch=readc();
while (!isdigit(ch)) ch=readc();
while (isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=readc();
return x;
}
int main(){
n=_read();
for (int i=1;i<=n;i++) a[i]=_read(),s[~a[i]&(1<<22)-1]=a[i];
for (int i=0;i<22;i++)
for (int j=0;j<1<<22;j++)
if (!(j>>i&1)&&s[j|1<<i]) s[j]=s[j|1<<i];
for (int i=1;i<=n;i++)
printf("%d ",s[a[i]]?s[a[i]]:-1);
return 0;
}