test20181019 B君的第二题

题意


分析

UPD:以前在口胡,现在重写一下。

这个快速子集和变换其实就是快速莫比乌斯变换。

先做莫比乌斯变换,然后直接组合。这样统计出来的有自己的真子集,直接减去就是了。

再做一个快速超集和变换,这个是拓展内容。

时间复杂度\(O(n2^n)\)

#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<string>
#include<vector>
#include<list>
#include<deque>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<complex>
#define rg register
#define il inline
#define co const
#pragma GCC optimize ("O0")
using namespace std;
template<class T> il T read()
{
    rg T data=0;
	rg int w=1;
    rg char ch=getchar();
    while(!isdigit(ch))
    {
		if(ch=='-')
			w=-1;
		ch=getchar();
	}
    while(isdigit(ch))
        data=10*data+ch-'0',ch=getchar();
    return data*w;
}
template<class T> il T read(rg T&x)
{
	return x=read<T>();
}
typedef long long ll;
const int INF=0x7fffffff;

const int MAXN=1<<20|7;
ll f[MAXN];

int main()
{
  freopen("lhasa.in","r",stdin);
  freopen("lhasa.out","w",stdout);
	rg int n,k;
	read(n);read(k);
	for(rg int i=1;i<=n;++i)
	{
		++f[read<int>()];
	}
	for(rg int i=0;i<k;++i) // 逐位递推 
		for(rg int j=0;j<1<<k;++j)
			if(j >> i & 1)
			{
				f[j] += f[j ^ (1 << i)];
			}
	for(rg int i=0;i<1<<k;++i) // 组合 
	{
		f[i]=f[i]*(f[i]-1)/2;
	}
	for(rg int i=0;i<k;++i) // 减去组合成自己的组合 
		for(rg int j=0;j<1<<k;++j)
			if(j >> i & 1)
			{
				f[j] -= f[j ^ (1 << i)];
			}
	for(rg int i=0;i<k;++i) // 加上超集的方案数 
		for(rg int j=0;j<1<<k;++j)
			if(j >> i & 1)
			{
				f[j ^ (1 << i)] += f[j];
			}
	for(rg int i=0;i<1<<k;++i)
	{
		printf("%lld\n",f[i]);
	}
//  fclose(stdin);
//  fclose(stdout);
    return 0;
}

posted on 2019-07-12 09:34  autoint  阅读(212)  评论(1编辑  收藏  举报

导航