D e s c r i p t i o n Description Description

给定一个大小为 n n n的可重集合,求这些集合的子集的所有子集的和(这里的子集都可重)能被 m m m整除的子集有多少个

数据范围:


S o l u t i o n Solution Solution

显然一个有 n n n个元素的可重集,设所有元素的和为 s u m sum sum,则它所有子集的和为 2 n − 1 × s u m 2^{n-1}\times sum 2n−1×sum

证明:
考虑每个元素对子集和的贡献,假设一个元素 x x x选了,那么无论其它元素选不选,它都有 x x x的贡献,而其它选择的方案有 2 n − 1 2^{n-1} 2n−1种( n − 1 n-1 n−1个数可选可不选),那么它的贡献就是 x × 2 n − 1 x\times 2^{n-1} x×2n−1
则总贡献即 ∑ x × 2 n − 1 = s u m × 2 n − 1 \sum x\times 2^{n-1}=sum\times 2^{n-1} ∑x×2n−1=sum×2n−1

这个结论有什么用呢?
这告诉我们,集合的个数无论多少,都仅只会多产生2的因子
举个栗子,假如一个子集的大小为 n n n,那么实际上会多出 n − 1 n-1 n−1个2这个因子

其实也就相当于如果一个集合的大小为 n n n,它的元素和为 s u m sum sum,显然它的子集和为 2 n − 1 × s u m 2^{n-1}\times sum 2n−1×sum

  1. 如果 m m m转换为二进制后后面至少有 n − 1 n-1 n−1个0,即它含有 2 n − 1 2^{n-1} 2n−1这个因子
    根据之前的结论,那么有 s u m × 2 n − 1 m o d m = s u m m o d m 2 n − 1 sum\times 2^{n-1} \mod m=sum\mod \frac m{2^{n-1}} sum×2n−1modm=summod2n−1m​
  2. 如果 m m m转换为二进制后面0不够多,设它的0有 l e n len len个(这个可以用 l o w b i t lowbit lowbit求出来),那么对于每个大小为 j j j的集合,如果 j ≥ l e n j\geq len j≥len,则它的选取方案是不受 j j j的影响的

换句话说,我们只需保存 l e n len len以内的答案,多于 l e n len len的都把它存到 l e n len len里面(因为如果 j ≥ l e n j\geq len j≥len,则题目跟背包没有区别)

所以,设 f i , j , k f_{i,j,k} fi,j,k​表示前 i i i个数,选了 j j j个数, m o d mod mod缩小后的 m m m的余数是 k k k的方案数
滚动后直接转移即可

由于 j j j的变大, k k k的上界会相对应的缩小,所以总的复杂度是 O ( n m ) O(nm) O(nm),需要适当卡常

T i p s : Tips: Tips:
由于大小为 n n n的集合对 m m m的影响却是 2 n − 1 2^{n-1} 2n−1,所以我们把 m m m乘2,这样方便转移


C o d e Code Code

#pragma GCC optimize(2)
%:pragma GCC optimize(3)
%:pragma GCC optimize("Ofast")
%:pragma GCC optimize("inline")
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
#define mod 1000000007
using namespace std;int n,m,a[5010],len,f[2][14][10010],nmd,Ans;
inline LL read()
{char c;LL d=1,f=0;while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;return d*f;
}
signed main()
{n=read();m=read()*2;int x=m;while(!(x&1)) len++,x>>=1;f[0][0][0]=1;for(register int i=1;i<=n;i++){a[i]=read();for(register int j=0;j<=len;j++) {nmd=m/(1<<j);for(register int k=0;k<nmd;k++) f[i&1][j][k]=f[i&1^1][j][k];//初始化,不能用memset,不然会T}for(register int j=0;j<=len;j++){nmd=m/(1<<j);//nmd=new modfor(register int k=0;k<nmd;k++){if(j==len) //>=len的部分都转移到len来{f[i&1][len][(k+a[i])%nmd]+=f[i&1^1][len][k];if(f[i&1][len][(k+a[i])%nmd]>mod) f[i&1][len][(k+a[i])%nmd]-=mod;}else {(f[i&1][j+1][(k+a[i])%(nmd/2)]+=f[i&1^1][j][k])%=mod;//注意每多放一个数,模数都要除以二if(f[i&1][j+1][(k+a[i])%(nmd/2)]>mod) f[i&1][j+1][(k+a[i])%(nmd/2)]-=mod;}}}}for(register int i=1;i<=len;i++) (Ans+=f[n&1][i][0])%=mod;printf("%d",Ans);
}

nssl 1522.简单数数题相关推荐

  1. python猜数游戏流程_python简单猜数游戏实例

    本文实例讲述了python简单猜数游戏.分享给大家供大家参考.具体实现方法如下: #!/usr/bin/env python import random number = random.randint ...

  2. 数数题(计数类 DP)做题记录

    数数题(计数类 DP)做题记录 CF1657E Star MST 我们称张无向完全图是美丽的当且仅当:所有和 \(1\) 相连的边的边权之和等于这张完全图的最小生成树的边权之和. 完全图点数为 \(n ...

  3. [XSY] 简单的数论题(数学、构造)

    简单的数论题 m(a3+b3)=n(c3+d3)m(a^3+b^3)=n(c^3+d^3)m(a3+b3)=n(c3+d3) 考虑因式分解(a3+b3),(c3+d3):考虑因式分解(a^3+b^3) ...

  4. CSDN挑战编程——《金色十月线上编程比赛第一题:小女孩数数》

    金色十月线上编程比赛第一题:小女孩数数 题目详情: [金色十月线上编程比赛规则] 一个小女孩正在用左手手指数数,从1数到n.她从拇指算作1开始数起,然后,食指为2,中指为3,无名指为4,小指为5.接下 ...

  5. js设计一个带开关的时钟_数电题:三个按键一个灯

    有这样一道数电题: 一个LED发光二极管由A.B.C三个独立按键控制,要求按压A.B.C三个按键中的任意一个都能对LED实现亮.灭控制(即每按压一次按键,LED发光状态改变一次).请用D触发器或JK触 ...

  6. 聊城大学计算机2014高数试题,高数真题14-15.docx

    高数真题14-15 河南省2014年普通高校等学校选拔优秀本科毕业生本科阶段学习考试高等数学选择题(每小题2分,共60分)函数的定义域是 ( ) A. B. C. D.2.已知, 则 ( ) A. B ...

  7. 15拆分成3个不同的自然数_小学二年级奥数训练题之分拆

    做奥数题有助于我们能力的提升,不仅在数学方面,其他方面也是很有帮助的,主要是让我们多动脑思考.下面为大家带来小学二年级奥数训练题. 小学二年级奥数训练题 整数分拆问题是一个古老而又十分有趣的问题.所谓 ...

  8. 2001考研数一真题解析

    2001考研数一真题解析

  9. C语言解决对给定的任一不超过1000的正整数n,简单地数一下,需要多少步(砍几下)才能得到n=1?

    /* 卡拉兹(Callatz)猜想: 对任何一个自然数n,如果它是偶数,那么把它砍掉一半:如果它是奇数,那么把(3n+1)砍掉一半.这样一直反复砍下去, 最后一定在某一步得到n=1.卡拉兹在1950年 ...

最新文章

  1. oracle省市表,省市之一 创建全国省市Sql表
  2. 条件随机场概率无向图模型的因子分解
  3. jsp:include page= /路径
  4. java map存放班级和姓名_Java 创建一个HashMap对象,并在其中添加学生的姓名和成绩,键为学生姓名,值为学生成绩,使用增强for循环遍历该HashMap,并输出学生成绩。...
  5. delphi cxgrid读取本地image_技术讨论 | PHP本地文件包含漏洞GetShell
  6. 你们网贷逾期最长多少时间,你们怎么处理的
  7. gh-ost 学习笔记
  8. 华为NP课程笔记23-VRRP
  9. c语言自动贩卖机找钱,c语言趣题之“找钱的方法数量 ”
  10. CIE 国际照明委员会
  11. 对类模板特化和函数模板重载的一点理解
  12. 计算机线连接方法,手机和电脑的常用连接方法比较
  13. Java编程题(3)
  14. eCharts改变饼图的默认颜色
  15. 算法学习过程入门篇(2)-算法初步
  16. 京淘商城后台管理系统
  17. python爬虫-采集英语翻译
  18. voip(语音电话)
  19. 狼人杀要做社交,绕不开语音视频连麦 | 深度
  20. Android使用Vitamio来打造自己的视频播放器

热门文章

  1. 11. Cryptocell-712安全引擎概述
  2. oracle sql获取本季度,oracle sql 获取本季度所有月份,上季度所有月份
  3. 前端防抖与节流超详细讲解
  4. swich...case加范围条件
  5. 【操作方法】windows防火墙添加出入站规则方法
  6. 【C/C++】typedef用法详解
  7. 路由与交换系列之企业级ipv6和AAA通讯实验(下)
  8. 《Android 应用案例开发大全(第3版)》——第2章,第2.3节壁纸的基本框架
  9. 解决报错,Ignored attempt to cancel a touchmove event with cancelable=false
  10. STM32的3种低功耗模式