hdu3929
二项式定理有两个性质,第一个是高中就接触过的,即奇数项(这里的奇数项与题目的奇数项定义不同)和偶数项系数之和相同
第二个也可以记住
阶乘分解质因数注意复习一下
这里拓展一个:$$\lfloor \frac{\lfloor\frac{n}{p}\rfloor}{q} \rfloor=\lfloor\frac{n}{pq}\rfloor$$
证明:设\(n=kp+r(0≤r<p)\),则\(LHS=\lfloor\frac{k}{q}\rfloor\),\(RHS=\lfloor\frac{k}{q}+\frac{r}{pq}\rfloor\);有\(\frac{r}{pq}<\frac{1}{q}\),我们将\(\frac{k}{q}\)看成\(k\)个\(\frac{1}{q}\)相加,将数轴上的每两个整数之间划分成\(q\)个均匀段,所以\(k\)个\(\frac{1}{q}\)相加会停留在某一个点,再加上一个小于\(\frac{1}{q}\)的数显然不会到达下一个位置。画图如下
当然这也告诉我们:中途一旦产生进位了,那么\(1\)的个数就要变化了
为什么?我们从竖式加法的角度考虑。从低位往高位进行加法,第一次进行的时候一定是两个\(1\)合成了一个\(0\),此时\(bitcnt(k)+bitcnt(n-k)\)比\(bitcnt(n)\)要多\(2\),然后进了一位,如果下一位是\(0+0\),那么\(bitcnt(k)+bitcnt(n-k)\)比\(bitcnt(n)\)多\(1\);如果下一位是\(0+1\)或者\(1+0\),那么继续进位并且\(bitcnt(k)+bitcnt(n-k)\)比\(bitcnt(n)\)要多\(3\);如果下一位是\(1+1\),那么\(bitcnt(k)+bitcnt(n-k)\)比\(bitcnt(n)\)要多\(3\)。然后继续下去就会发现\(bitcnt(k)+bitcnt(n-k)\)一定比\(bitcnt(n)\)要多
为什么这里是覆盖奇数次?因为偶数不改变奇偶性
这个典型的容斥原理简单来说,就是先求每个\(a_i\)的子集,然后再求每两个\(a_i\)交集的子集,但是这里不是直接减掉,是要减掉两倍这么多,然后再求每三个\(a_i\)交集的子集,但是是加上四倍这么多,以此类推,下面以三个集合的文氏图来理解
先求每个\(a_i\)的子集
再减掉每两个\(a_i\)的交集的两倍
再加上三个\(a_i\)的交集的四倍
很显然就是被覆盖了奇数次的集合
由于这道题目只用统计个数,我们没有必要每次去算出具体的集合,而是可以直接累加贡献,所以时间复杂度为\(O(2^m)\),具体见代码
代码可以看看这篇文章
这篇文章的代码:
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<iomanip>
#include<cmath>
#include<cstring>
#include<vector>
#define ll __int64
#define pi acos(-1.0)
#define MAX 50000
using namespace std;
ll an[16],ans;
int n;
int get(ll n)
{
int t=0;
while(n){
n-=(n&-n);
t++;
}
return t;
}
void dfs(int i,ll sum,ll k)//递归版容斥原理
{
ans+=(1ll<<(get(sum)))*k;
for(int j=i+1;j<n;j++)
dfs(j,sum&an[j],-2*k);
}
ll solve(int n)//迭代版容斥原理
{
ll ans=0,res,m=1;
int i,j,temp;
for(i=1;i<(1<<n);i++){
temp=0;
for(j=0;j<n;j++){
if(i&(1<<j)){
temp++;
if(temp==1) res = an[j];
else res=res&an[j];
}
}
res=(1<<get(res));
ans+=m*res;
m*=-2;
}
return ans;
}
int main(){
int i,t,k=1;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%I64d",&an[i]);
ans=0;
for(i=0;i<n;i++)
dfs(i,an[i],1);
printf("Case #%d: %I64d\n",k++,ans);
}
return 0;
}