• CF449D Jzzhu and Numbers



    题解

    刚刚学习了高维前缀和
    这道题就肥肠简单了

    高维前缀和其实原理肥肠简单
    就是每次只考虑一维,然后只做这一维的前缀和
    最后求出的就是总前缀和了

    那么对于这道题
    也就很简单了
    发现选择的所有数每一位都必须不能所有数都是1
    那么可以考虑一个简单的容斥
    (g_i)表示至少(i)的二进制下的这几维为1的方案数
    那么就可以用类似高维前缀和来统计(g_i)
    也就是统计ta作为哪些元素的子集
    然后枚举选那几位
    答案就是((-1)^{|S|}{2^{g_{i}}})

    代码

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    const int M = 2000005 ;
    const int mod = 1e9 + 7 ;
    using namespace std ;
    inline int read() {
    	char c = getchar() ; int x = 0 , w = 1 ;
    	while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
    	while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
    	return x*w ;
    }
    
    int n , val[M] , f[M] , pw2[M] , ans ;
    
    inline int chk(int S) {
    	int ret = 0 ;
    	for(int i = 1 ; i <= 20 ; i ++)
    		if(S & (1 << (i - 1)))
    			++ ret ;
    	return ret ;
    }
    int main() {
    	n = read() ;
    	for(int i = 1 ; i <= n ; i ++) {
    		val[i] = read() ;
    		f[val[i]] ++ ;
    	}
    	pw2[0] = 1 ;
    	for(int i = 1 ; i <= n ; i ++) pw2[i] = 1LL * pw2[i - 1] * 2 % mod ;
    	for(int i = 0 ; (1 << i) <= 1000000 ; i ++) {
    		for(int j = (1 << 20) - 1 ; j >= 0 ; j --)
    			if(!(j & (1 << i)))
    				f[j] = (f[j] + f[j ^ (1 << i)]) % mod ;
    	}
    	for(int i = 0 , sz ; i < (1 << 20) ; i ++) {
    		sz = chk(i) ;
    		if(sz & 1) sz = -1 ;
    		else sz = 1 ;
    		ans = ((ans + sz * (pw2[f[i]] - 1)) % mod + mod) % mod ;
    	}
    	printf("%d
    ",ans) ;
    	return 0 ;
    }
    
  • 相关阅读:
    彻底弄懂三段式状态机
    关于verilog的有符号数与无符号数的转换
    关于win10系统安装vivado 2017.1 .2 .3 报runtime error 问题解决办法 亲测有效
    python的列表拷贝
    PYTHON
    保存linux下当前目录下所有文件的相对路径
    Git 命令及使用经验
    讯飞SDK的使用
    DE4加DVI子板实现静态图片显示
    HDL代码风格建议(2)乘法器和DSP推断
  • 原文地址:https://www.cnblogs.com/beretty/p/10526908.html
Copyright © 2020-2023  润新知