51nod1406 与查询 dp

来源:互联网 发布:淘宝商品详情页面html 编辑:程序博客网 时间:2024/06/14 09:58

Description


有n个整数。输出他之中和x相与之后结果为x的有多少个。x从0到1,000,000

Input


第一行输入一个整数n。(1<=n<=1,000,000).
第二行有n个整数a[0],a[1],a[2],…a[n-1],以空格分开.(0<=a[i]<=1,000,000)

Output


对于每一组数据,输出1000001行,第i行对应和i相与结果是i的有多少个数字。

Solution


一个很显然的性质是若a&b==a则对于a的二进制上的每一位1都在b上同为1,这个可以形象地理解为两个集合的交操作,若AB=AAB

考虑怎么统计答案。设f[x]是第x行的答案。若a是b的一个子集,那么每一个f[b]都要统计到f[a]中。但是这样做是会发生重复的,解决的方法就是从高位到低位倒着枚举即可

这题似乎卡常要读入输出优化
题目的输出解释有点坑,第i行输出的是i-1的答案

Code


#include <stdio.h>#include <string.h>#define rep(i,st,ed) for (int i=st;i<=ed;++i)#define drp(i,st,ed) for (int i=st;i>=ed;--i)#define N 1<<21|1int f[N];int read() {    int x=0; char ch=getchar();    for (;ch<'0'||ch>'9';ch=getchar());    for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());    return x;}void writeln(int x) {    int prt[10]={};    do {prt[++prt[0]]=x%10;} while (x/=10);    drp(i,prt[0],1) putchar(prt[i]+'0');    putchar('\n');}int main(void) {    int n=read();    rep(i,1,n) {        f[read()]++;    }    drp(i,20,0) {        rep(j,0,1000000) {            if ((1<<i)&j) {                f[j^(1<<i)]+=f[j];            }        }    }    rep(i,0,1000000) {        writeln(f[i]);    }    return 0;}
原创粉丝点击