【题解】与查询 [51nod1406]

【题解】与查询 [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)

【Code】

#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("");
}
原文地址:https://www.cnblogs.com/Xing-Ling/p/11348359.html