【题解】与查询 [51nod1406]
阅读原文时间:2023年07月08日阅读:1

【题解】与查询 [51nod1406]

传送门:与查询 \([51nod1406]\)

给出 \(n\) 个整数,对于 \(x \in [0,1000000]\),分别求出在这 \(n\) 个整数当中同 \(x\) 求与之后结果为 \(x\) 的有多少个。

【样例】

样例输入:
3
2 3 3

样例输出:
3
2
3
2
0
0
...
...
...
0
(一共1000001个数,后面一共999997个0)

【数据范围】

\(100\%\) \(1 \leqslant N \leqslant 10^6,\) \(1 \leqslant a[i] \leqslant 10^6\)

用 \(dp[i]\) 表示与 \(i\) 求与等于 \(i\) 的数的个数。

首先,一个数同它自己求与还是等于它自己,所以对于,\(dp[i]\) 的初始值就是给出的序列中 \(i\) 出现的次数。

对于某一个二进制数 \(a\),将其任意一个为 \(0\) 的位变为 \(1\) ,得到二进制数 \(b\)。

可知:

同 \(a\) 求与等于 \(a\) 的数同 \(b\) 求与不一定等于 \(b\),

同 \(b\) 求与等于 \(b\) 的数同 \(a\) 求与一定等于 \(a\)。

即 \(b\) 的方案一定可以满足 \(a\) 的需求。

所以 \(dp\) 方程为:\(dp[j]+=dp[j \oplus (1<<i)]\),其中 \(j \in [0,10^6],\) \(j\) \(\And (1<<i)==0\) 且 \(j \oplus (1<<i) \leqslant 10^6\)

由于数据输出过多,需要自己写快输,否则会全 \(TLE\) 。

时间复杂度为 \(O(MlogM)\),其中 \(M=10^6\) 。

#include<algorithm>
#include<cstdio>
#define Re register int
const int N=1e6;
int n,a,dp[N+3];
inline void in(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
inline void out(int x){
    if(x>9)out(x/10);
    putchar(x%10+'0');
}
int main(){
    in(n);
    for(Re i=1;i<=n;i++)in(a),++dp[a];
    for(Re i=0;i<20;i++)
        for(Re j=0;j<=N;++j)
            if(!(j&(1<<i))&&(j^(1<<i))<=N)dp[j]+=dp[j^(1<<i)];
    for(Re j=0;j<=N;++j)out(dp[j]),puts("");
}