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\)种洗牌方法,每种洗牌方法是一种置换.保证任意多次洗牌都可用这\( ...
随机推荐
- L - Looking for Taste Gym - 101991L 二进制枚举/思维
方法一:因为最多是10的六次方,所以可以直接枚举二进制上的每一位来得到最优结果. AC代码: #include<iostream> #include<stack> #inclu ...
- LCD之mipi DSI接口驱动调试流程【转】
转自:http://blog.csdn.net/liwei16611/article/details/68146912 1.LCD MIPI DSI协议 MIPI-DSI是一种应用于显示技术的串行接口 ...
- 64_t2
texlive-biblatex-chem-doc-svn42065-33.fc26.2.no..> 24-May-2017 15:44 1044190 texlive-biblatex-che ...
- Delphi 10 seattle 去掉自带的代码连接线
- 关于text-decoration无法清除继承的问题
因为text-decoration的值可以叠加,所以即使设置了none,浏览器也是看成是叠加,而不是清除的意思.
- 【题解】BZOJ 3065: 带插入区间K小值——替罪羊树套线段树
题目传送门 题解 orz vfk的题解 3065: 带插入区间K小值 系列题解 一 二 三 四 惨 一开始用了一种空间常数很大的方法,每次重构的时候merge两颗线段树,然后无限RE(其实是MLE). ...
- tomcat打开gzip、配置utf-8
在部署描述文件中配置如下内容:(web.xml) 打开gzip compression="on"配置utf-8 URIEncoding="UTF-8" < ...
- POJ 1386 Play on Words(单词建图+欧拉通(回)路路判断)
题目链接:http://poj.org/problem?id=1386 题目大意:给你若干个字符串,一个单词的尾部和一个单词的头部相同那么这两个单词就可以相连,判断给出的n个单词是否能够一个接着一个全 ...
- HDU 2647 Reward(拓扑排序+判断环+分层)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2647 题目大意:要给n个人发工资,告诉你m个关系,给出m行每行a b,表示b的工资小于a的工资,最低工 ...
- kNN算法笔记
kNN算法笔记 标签(空格分隔): 机器学习 kNN是什么 kNN算法是k-NearestNeighbor算法,也就是k邻近算法.是监督学习的一种.所谓监督学习就是有训练数据,训练数据有label标好 ...