【题目描述】 小 X 是一个孤独的 OIer,退役后他发现他无法和其他人找到共同的话题。 好在小 X 有 M 名同学,小 X 希望通过 K 天的交流拉近与他们的关系。 这 M 名同学可能感兴趣的话题共有 N 种,我们用一个 N 位的二进制数 Ai 来 表示一位同学对于各个话题是否感兴趣,例如,当 N=3,Ai=二进制数 110(即 十进制数 6),表示第 i 位同学对第 1、第 2 个话题感兴趣,而对第 3 个话题不感 兴趣。 每天,小 X 会选择一位同学,与其交流一个他感兴趣的话题。由于 OIer 的 记忆只有 7 秒,所以小 X 每天与同学交流的话题必须都一样。 现在,小 X 想要知道他有多少种不同的方式选择每天交流的同学,使得他能 够找到至少一个话题,顺利地完成和他们的交流。两种选取方案不同,当且仅当 在某一天小 X 选择的同学不同。 由于答案可能很大,输出其对 10 9+7 取模的结果。 【输入格式】 从文件 loneliness.in 中读取数据。 第一行一个整数 Num,表示测试点编号,以便选手方便地获得部分分,你可 能不需要用到这则信息,样例中 Num 的含义为数据范围与某个测试点相同。 接下来一行三个整数 N、M、K,含义见题面描述。 接下来一行 M 个整数 Ai,表示每名同学可能感兴趣的话题,以十进制的方 式给出。 【输出格式】 一行一个整数,表示方案数对 10 9+7 取模的结果。 【样例 1 输入】 2 2 3 4 1 2 3 【样例 1 输出】 31 【样例 1 解释】 在这个样例中,我们只需要不同时选取 1 号和 2 号同学就能够保证小 X 能够 找到合适的话题。 因此方案数为(不选 1 号的方案数+不选 2 号的方案数-不选 1 号且不选 2 号 的方案数)=16+16-1=31。
根据容斥原理,答案就应该是每个话题的方案数,减去两个话题的方案数,加上三个话题的方案数,再减去四个话题的方案数,…
分析一下复杂度,计算枚举话题的方案数乘上每次统计当前这种话题的方案数O(2n∗m2n∗m)
这个会时间超限,关键就是在统计方案数。
一个数,如果对某个方案贡献,就是这个数是它的子集,
考虑一种更加优秀的枚举子集办法。
#include<bits/stdc++.h>
#define f(i,l,r) for(i=(l);i<=(r);i++)
using namespace std;
const int MAXN=100005,MOD=1e9+7;
int num,n,m;
long long K;
int sta[MAXN];
long long opt[1<<25];
long long ans;
long long Pow(long long a,long long num)
{
long long res=1;
for(;num;num>>=1){
if(num&1) res=(res*a)%MOD;
a=(a*a)%MOD;
}
return res;
}
bool cal(int x)
{
int res=0;
while(x){
res++;
x-=(x&(-x));
}
if(res&1) return true;
return false;
}
int main()
{
ios::sync_with_stdio(false);
int i,j;
cin>>num;
cin>>n>>m>>K;
f(i,1,m){
cin>>sta[i];
for(j=sta[i];j;j=(j-1)&(sta[i])){
opt[j]++;
}
}
f(i,1,(1<<n)-1){
if(!opt[i]) continue;
if(cal(i)) ans=(ans+Pow(opt[i],K))%MOD;
else ans=(ans-Pow(opt[i],K)+MOD)%MOD;
}
cout<<(ans+MOD)%MOD<<endl;
return 0;
}
#include<cstdio>
#include<iostream>
#include<algorithm>
#define N 2000000
#define mo 1000000007
#define LL long long
using namespace std;
LL ans;
int n,m,k,x,s[N],hjy[N];
LL mul(LL x,LL y){
if (y==1) return x;
LL o=mul(x,y/2);
o=(o*o)%mo;
if (y%2==1) o=(o*x)%mo;
return o;
}
inline void dfs(int x,int dep){
if (dep==n) {
int o=x,p=0;
while (o){
if (o%2==1) p++;
o>>=1;
}
if (p==0) return;
if (p%2==0) ans=(ans-mul(s[x],k)+mo)%mo;
else ans=(ans+mul(s[x],k))%mo;
return;
}
dfs((x<<1)+1,dep+1);
dfs(x<<1,dep+1);
}
int main(){
freopen("a.in","r",stdin);
// freopen("loneliness.in","r",stdin);
// freopen("loneliness.out","w",stdout);
scanf("%d",&x);
scanf("%d%d%d",&n,&m,&k);
for (int i=1;i<=m;i++) {
scanf("%d",&x);
s[x]++;
}
for (int i=0;i<n;i++)
for (int j=1;j<=(1<<(n+1)-1);j++) if (j&(1<<i)) s[j^(1<<i)]+=s[j];
dfs(0,0);
printf("%lld",ans);
}
#include<bits/stdc++.h>
#define mo 1000000007
#define ll long long
using namespace std;
ll m,n,k,f[1100010],g[1100010],x,ans;
ll po(ll x,ll y){ll z=1;while (y){if (y%2==1)z=(x*z)%mo;x=(x*x)%mo;y/=2;}return z;}
int main(){
//freopen("loneliness.in","r",stdin);
//freopen("loneliness.out","w",stdout);
cin>>n;
cin>>n>>m>>k;
for (int i=1;i<=m;i++){scanf("%d",&x);g[x]++;}
f[0]=-1;
for (int i=0;i<(1<<n);i++)
for (int j=1;j<(1<<n);j*=2)
if ((i&j)==0)f[i+j]=f[i]*(-1);
for (int i=1;i<(1<<n);i*=2)
for (int j=0;j<(1<<n);j++)
if ((i&j)!=0) g[j-i]+=g[j];
for (int i=1;i<(1<<n);i++)ans=(ans+f[i]*po(g[j],k)+mo)%mo;
cout<<ans<<endl;
return 0;
}