取数字(dp优化)
取数字(dp优化)
给定n个整数\(a_i\),你需要从中选取若干个数,使得它们的和是m的倍数。问有多少种方案。有多个询问,每次询问一个的m对应的答案。
\(1\le n\le 200000,1\le m\le 100,1\le q\le 30,-10^9\le a_i\le 10^9\)。
首先有一个暴力dp:\(f[i][j]\)表示选到第i个数,和mod m是j的方案数。但是显然,这个dp是\(O(nm)\)的,然后就tle了。
换一个思路dp?由于我们只需要一个数模m的值,可以先把所有数模m放到桶里,用\(f[i][j]\)表示选到第i个桶,余数和为j的方案数。那么,枚举这一个桶放了多少数k(rh奇怪的dp方法),\(f[i][j+ki]+=f[i-1][j]*\binom{b[i]}{k}\)。
这个dp是\(O(nm^2)\)的,能过50%。先把代码放上来:
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const LL maxn=4e5+5, maxm=105, mod=1e9+7;
LL n, q, m, a[maxn], b[maxm], f[maxm][maxm];
LL fac[maxn], inv[maxn];
LL C(LL x, LL y){ return fac[x]*inv[y]%mod*inv[x-y]%mod; }
LL fpow(LL a, LL x){
LL ans=1, base=a;
for (; x; x>>=1, base*=base, base%=mod)
if (x&1) ans*=base, ans%=mod;
return ans;
}
int main(){
scanf("%lld%lld", &n, &q);
fac[0]=1; inv[0]=1;
for (LL i=1; i<maxn; ++i) fac[i]=(i*fac[i-1])%mod, inv[i]=fpow(fac[i], mod-2);
for (LL i=1; i<=n; ++i) scanf("%lld", &a[i]);
while (q--){
memset(b, 0, sizeof(b));
memset(f, 0, sizeof(f));
scanf("%lld", &m);
for (LL i=1; i<=n; ++i) ++b[(a[i]%m+m)%m];
f[0][0]=fpow(2, b[0]);
for (LL i=1; i<m; ++i){ //第几个桶
for (LL w=0; w<m; ++w) //所有数的和的余数是w
for (LL j=0; j<=b[i]; ++j) //这个桶取了多少数
(f[i][(j*i+w)%m]+=f[i-1][w]*C(b[i], j))%=mod;
}
printf("%lld\n", f[m-1][0]);
}
return 0;
}
我们在\((f[i][(j*i+w)\%m]+=f[i-1][w]*C(b[i], j))\%=mod;\)这行里可以发现:虽然j枚举到了b[i],但是\((j*i+w)\)模了m。因此,只要枚举\(j=[0,m-1]\)就行了!
所以说:
- dp要多考虑几种方法突破。
- dp方程里如果带模数,有时是可以优化的。
- 只要不把求状态的顺序颠倒,可以交换dp中两个循环的位置
#include <cctype>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const LL maxn=4e5+5, maxm=105, mod=1e9+7;
LL n, q, m, a[maxn], b[maxm], f[maxm][maxm];
LL fac[maxn], inv[maxn], pre[maxn];
inline int min(LL x, LL y){ return x<y?x:y; }
LL C(LL x, LL y){ return fac[x]*inv[y]%mod*inv[x-y]%mod; }
LL fpow(LL a, LL x){
LL ans=1, base=a;
for (; x; x>>=1, base*=base, base%=mod)
if (x&1) ans*=base, ans%=mod;
return ans;
}
int getint(){
char c; int flag=1, re=0;
for (c=getchar(); !isdigit(c); c=getchar())
if (c=='-') flag=-1;
for (re=c-48; c=getchar(), isdigit(c); re=re*10+c-48);
return re*flag;
}
int main(){
scanf("%lld%lld", &n, &q);
fac[0]=1; inv[0]=1;
for (LL i=1; i<maxn; ++i) fac[i]=(i*fac[i-1])%mod, inv[i]=fpow(fac[i], mod-2);
for (LL i=1; i<=n; ++i) scanf("%lld", &a[i]);
while (q--){
memset(b, 0, sizeof(b));
memset(f, 0, sizeof(f));
m=getint();
for (LL i=1; i<=n; ++i) ++b[(a[i]%m+m)%m];
f[0][0]=fpow(2, b[0]);
for (LL i=1; i<m; ++i){ //第几个桶
for (LL j=0; j<=b[i]; ++j){
if (j<m) pre[j%m]=0;
(pre[j%m]+=C(b[i], j))%=mod;
}
for (LL w=0; w<m; ++w) //所有数的和的余数是w
for (LL j=0; j<=min(m-1, b[i]); ++j) //这个桶取了多少数
(f[i][(j*i+w)%m]+=f[i-1][w]*pre[j])%=mod;
}
printf("%lld\n", f[m-1][0]);
}
return 0;
}
取数字(dp优化)的更多相关文章
- 连续取数字DP使值最大HDU2697
题意: 有n个数,每个数都有价钱,连续的取可以获得len*len的利益,使利益最大. 思路: 三维DP,1.2.3维分别是第i个,剩余多少钱,从后往前连续的有几个. #define IOS ios_b ...
- [总结]一些 DP 优化方法
目录 注意本文未完结 写在前面 矩阵快速幂优化 前缀和优化 two-pointer 优化 决策单调性对一类 1D/1D DP 的优化 \(w(i,j)\) 只含 \(i\) 和 \(j\) 的项--单 ...
- Slope Trick:解决一类凸代价函数DP优化
[前言] 在补Codeforce的DP时遇到一个比较新颖的题,然后在知乎上刚好 hycc 桑也写了这道题的相关题解,这里是作为学习并引用博客的部分内容 这道题追根溯源发现2016年这个算法已经在API ...
- DP 优化方法大杂烩 & 做题记录 I.
标 * 的是推荐阅读的部分 / 做的题目. 1. 动态 DP(DDP)算法简介 动态动态规划. 以 P4719 为例讲一讲 ddp: 1.1. 树剖解法 如果没有修改操作,那么可以设计出 DP 方案 ...
- 蓝桥杯历届试题 地宫取宝 dp or 记忆化搜索
问题描述 X 国王有一个地宫宝库.是 n x m 个格子的矩阵.每个格子放一件宝贝.每个宝贝贴着价值标签. 地宫的入口在左上角,出口在右下角. 小明被带到地宫的入口,国王要求他只能向右或向下行走. 走 ...
- NOIP2015 子串 (DP+优化)
子串 (substring.cpp/c/pas) [问题描述] 有两个仅包含小写英文字母的字符串 A 和 B.现在要从字符串 A 中取出 k 个 互不重 叠 的非空子串,然后把这 k 个子串按照其在字 ...
- 【学习笔记】动态规划—各种 DP 优化
[学习笔记]动态规划-各种 DP 优化 [大前言] 个人认为贪心,\(dp\) 是最难的,每次遇到题完全不知道该怎么办,看了题解后又瞬间恍然大悟(TAT).这篇文章也是花了我差不多一个月时间才全部完成 ...
- Codevs 1305 Freda的道路(矩阵乘法 DP优化)
1305 Freda的道路 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 大师 Master 题目描述 Description Freda要到Rainbow的城堡去玩了.我们可以认 ...
- DP 优化小技巧
收录一些比较冷门的 DP 优化方法. 1. 树上依赖性背包 树上依赖性背包形如在树上选出若干个物品做背包问题,满足这些物品连通.由于 01 背包,多重背包和完全背包均可以在 \(\mathcal{O} ...
随机推荐
- Linux网络工具lsof和netstat
lsof全名为list opened files,即列举系统中已经被打开的文件,基本使用如下: (1) 查看/etc/passwd使用情况 lsof /etc/password (2) 查看监听的so ...
- C++11 auto和decltype推导规则
VS2015下测试: decltype: class Foo {}; int &func_int_r(void) { int i = 0; return i; }; int && ...
- 人脸识别FaceNet+TensorFlow
一.本文目标 利用facenet源码实现从摄像头读取视频,实时检测并识别视频中的人脸.换句话说:把facenet源码中contributed目录下的real_time_face_recognition ...
- 侯捷STL学习(六)--深入list && Iterator traits
第十三,四节 深度探索list(上,下) list Gnu2.9源代码实现 注意node代码和图示的位置 实现前闭后开,增加一个空白节点 用的分配器alloc Iterator智能指针,需要知道结点n ...
- node与vue结合的前后端分离跨域问题
第一点:node作为服务端提供数据接口,vue使用axios访问接口, 安装axios npm install axios --save 安装完成后在main.js中增加一下配置: import ax ...
- 运动事件Motion Events
备注:运动事件,也是加速度时间,一般像摇晃手机就属于运动事件 监听运动事件对于UI控件有个前提就是监听对象必须是第一响应者(对于UIViewController视图控制器和UIAP ...
- Android CTS(frome google)
Compatibility Test Suite How does the CTS work? The Compatibility Test Suite (CTS) is a free, commer ...
- Aborted connection+druid
试一试setTimeBetweenEvictionRunsMillis +setMaxEvictableIdleTimeMillis小于 mysql的wait_timeout
- 使用LaTeX按IEEE模板写论文时的参考文献管理方法(BibTeX使用小结)
之前用LaTeX写论文时,参考文献都是手动添加管理的,真是让人很抓狂.所以这次趁着假期,简单看了一下怎么使用BibTeX对参考文献进行管理,这里以IEEE的最新模板为例. 首先说明,我之前用的是MiK ...
- XMPP协议相关基础概念(Strophe学习笔记)
相关资料: XMPP官网http://xmpp.org/xmpp-software/libraries/ nginx的转发配置http://mineral.iteye.com/blog/448260 ...