Codechef APRIL14 ANUCBC Cards, bags and coins 背包DP变形
题目大意
有n个数字,选出一个子集,有q个询问,求子集和模m等于0的方案数%1000000009。(n <= 100000,m <= 100,q <= 30)
假设数据很小,我们完全可以做一个背包。
我们沿着背包的思路,看能不能给物品分一下类,由于m比较小,完全按N个数字模M后的值进行分类,这样就变成了一个多重背包的问题。(转移时要乘上一个组合数)
这时候的时间复杂度是n*m,还是不能过。
对于DP时所枚举到的模m后余数j,它所进行的状态转移是一定的,如果把这些转移先预处理出来,时间复杂度就能得到有效减小。
分析一下,转移方程是 F[i][j] = sigma(F[i][(j-i*k+m)%m]*C(count[i], k))%MOD,可以发现,(j-i*k+m)%m的值最多也只有m个,根本不需要枚举count[i]个这么多。
设t = (i*k)%m,G[i][t] = sigma(C(count[i], k)) (k = 0..count[i] 且 i*k%m == t),G数组可以在O(n)的时间内预处理出来。
新的转移方程就可以整理为 F[i][j] = sigma(F[i][(j-t+m)%m]*G[i][t])%MOD。 总的时间复杂度为O(n+m^3)。
问题还没有结束,G数组的计算也需要一定的技巧。如果计算每个G[i][t]的值都算一次逆元和组合数,时间复杂度起码要加上一个log,会TLE。
仔细分析可以发现,所计算的组合数C(count[i], k) (k = 0..count[i]),k是严格递增的,设temp = C(count[i], k-1),则C(count[i], k) = temp*(count[i]-(k-1))*inv[k]。
inv数组可以利用逆元打表O(n)的方法来实现,具体可参考博文:http://blog.csdn.net/guhaiteng/article/details/52123385
程序对拍过,但运行速度较慢。
#include <cstdio>
#include <cstring> using namespace std; typedef long long LL;
const int maxn = ;
const int MOD = ;
int n, m, Q;
int ccount[];
LL g[][], inv[maxn], f[][];
int a[maxn], ans; void add(LL &x, LL y)
{
x += y;
if (x >= MOD)
x -= MOD;
} void prepare()
{
for (int i = ; i < m; ++i)
ccount[i] = ;
for (int i = ; i <= n; ++i)
{
int temp = (a[i]%m+m)%m;
ccount[temp] ++;
}
for (int i = ; i < m; ++i)
for (int j = ; j < m; ++j)
g[i][j] = ;
for (int i = ; i < m; ++i)
{
LL temp = ccount[i];
add(g[i][], );
add(g[i][i%m], ccount[i]);
for (int j = ; j <= ccount[i]; ++j)
{
(temp *= (ccount[i]-(j-))) %= MOD;
(temp *= inv[j]) %= MOD;
add(g[i][(i*j)%m], temp);
}
}
} void dp()
{
memset(f, , sizeof(f));
f[][] = g[][];
for (int i = ; i < m; ++i)
for (int j = ; j < m; ++j)
for (int k = ; k < m; ++k)
{
LL temp = f[i-][(j-k+m)%m]*g[i][k]%MOD;
add(f[i][j], temp);
}
ans = f[m-][];
} int main()
{
inv[] = ;
for (int i = ; i <= ; ++i)
inv[i] = LL(MOD-MOD/i)*inv[MOD%i]%MOD;
int Task;
scanf("%d", &Task);
while (Task --)
{
scanf("%d %d", &n, &Q);
for (int i = ; i <= n; ++i)
scanf("%d", &a[i]);
while (Q --)
{
scanf("%d", &m);
prepare();
dp();
printf("%d\n", ans);
}
}
return ;
}
Codechef APRIL14 ANUCBC Cards, bags and coins 背包DP变形的更多相关文章
- [CC-ANUCBC]Cards, bags and coins
[CC-ANUCBC]Cards, bags and coins 题目大意: 给你\(n(n\le10^5)\)个数,\(q(q\le30)\)次询问,问从中选取若干个数使得这些数之和为\(m(m\l ...
- BZOJ 1004: [HNOI2008]Cards( 置换群 + burnside引理 + 背包dp + 乘法逆元 )
题意保证了是一个置换群. 根据burnside引理, 答案为Σc(f) / (M+1). c(f)表示置换f的不动点数, 而题目限制了颜色的数量, 所以还得满足题目, 用背包dp来计算.dp(x,i, ...
- CodeChef Cards, bags and coins [DP 泛型背包]
https://www.codechef.com/problems/ANUCBC n个数字,选出其一个子集.求有多少子集满足其中数字之和是m的倍数.n $\le$ 100000,m $\le$ 100 ...
- SGU 415. Necessary Coins ( 背包dp )
题意大概是:给出N个硬币, 面值为a_i, 问要凑成X元哪些硬币是不可或缺的.1 ≤ N ≤ 200, 1 ≤ x ≤ 10^4 直接枚举, 然后就是01背包了. 为了不让复杂度多乘个N, 我们就从左 ...
- Robberies (01背包dp变形)
题意:一个强盗要抢劫银行又不想被抓到,所以要进行概率分析求他在不被抓的情况下能抢最多的钱.他给定T(样例个数),N(要抢的银行的个数),P(被抓的概率要小于P)Mj(强盗能抢第j个银行Mj元钱),Pj ...
- PAT甲题题解-1068. Find More Coins (30)-dp,01背包
一开始没多想,虽然注意到数据N<=10^4的范围,想PAT的应该不会超时吧,就理所当然地用dfs做了,结果最后一组真的超时了.剪枝啥的还是过不了,就意识到肯定不是用dfs做了.直到看到别人说用0 ...
- Codeforces Round #207 (Div. 1) D - Bags and Coins 构造 + bitset优化dp + 分段查找优化空间
D - Bags and Coins 思路:我们可以这样构造,最大的那个肯定是作为以一个树根,所以我们只要找到一个序列a1 + a2 + a3 .... + ak 并且ak为 所有点中最大的那个,那么 ...
- UVA 562 Dividing coins --01背包的变形
01背包的变形. 先算出硬币面值的总和,然后此题变成求背包容量为V=sum/2时,能装的最多的硬币,然后将剩余的面值和它相减取一个绝对值就是最小的差值. 代码: #include <iostre ...
- 【BZOJ1004】【HNOI2008】Cards 群论 置换 burnside引理 背包DP
题目描述 有\(n\)张卡牌,要求你给这些卡牌染上RGB三种颜色,\(r\)张红色,\(g\)张绿色,\(b\)张蓝色. 还有\(m\)种洗牌方法,每种洗牌方法是一种置换.保证任意多次洗牌都可用这\( ...
随机推荐
- filezilla显示隐藏文件
我们在习惯使用flashfxp等工具,但是随着主机商限制较多,这些老的FTP工具不怎么好用了,比如主机商会推荐使用到Filezilla等工具.但是比如息壤主机,我们在管理linux环境下htacess ...
- Shell-history命令加记录用户IP
记录输入的命令 history命令可以查看用户输入过的命令,一个典型history命令输出如下: 980 2017-05-29 20:17:37 cd - 981 2017-05-29 20:17:4 ...
- nvidia tx1使用记录--基本环境搭建
前言 之前有专门写过一篇nvidia tk1使用记录--基本环境搭建,本以为自己有过tk1的经验后,在tx1上搭建和它一样的环境会轻车熟路,结果却是在nvidia tx1上花的时间居然比tk1还多.我 ...
- elk系列8之logstash+redis+es的架构来收集apache的日志【转】
preface logstash--> redis --> logstash --> es这套架构在讲究松耦合关系里面是最简单的,架构图如下: 解释下这个架构图的流程 首先前端log ...
- CentOS7安装Hadoop2.7完整步骤
总体思路,准备主从服务器,配置主服务器可以无密码SSH登录从服务器,解压安装JDK,解压安装Hadoop,配置hdfs.mapreduce等主从关系. 1.环境,3台CentOS7,64位,Hadoo ...
- Oracle 序列(sequence)的创建、修改及删除
1.Oracle 创建序列化:create sequence xxxx create sequence student_id minvalue --最小值 nomaxvalue --不设置最大值(由机 ...
- 响应式设计:根据不同设备引不同css样式
<link rel="stylesheet" media="screen and (max-width:600px)" href="small. ...
- MySQL5.7 centos7.2 yum 安装
1.配置YUM源 在MySQL官网中下载YUM源rpm安装包:http://dev.mysql.com/downloads/repo/yum/ # 下载mysql源安装包 shell> wge ...
- day6 time和datetime模块
time模块 time模块提供各种操作时间的函数 #1.时间戳 1970年1月1日之后的秒 #2.元组 包含了:年.日.星期等... time.struct_time #3.格式化的字符 ...
- day1 str字符串常用方法
字符串是编程中常用的类型,字符型在内存中是以单个形式存储的,比如name = "alex",在内存中存储的形式为["a","l"," ...