题意:给你一个长度为n序列,和一个数m,问这个序列有多少个子序列,满足这个子序列的所有子序列的和是m的倍数?答案对1e9 + 7取模,n, m范围到5e3;

思路:容易发现,如果一个子序列的长度是n,子序列的所有的元素的和是sum的话,它的所有的子序列的和是sum * 2 ^ (n - 1),那么我们发现,一个序列的所有子序列的和与子序列的和以及子序列的长度有关,我们容易想O(n^2 * m)的DP。设dp[i][j][k]为前i个数,长度为j的子序列中子序列的和是k的元素的个数。每扫到一个新的元素,有两种决策:1:不加这个数dp[i + 1][j][k] += dp[i][j][k];2:加这个数dp[i + 1][j +1][k + a[i + 1] += dp[i][j][k]。每次转移O(n * m),总复杂度O(n ^ 2 * m).

我们现在考虑优化一下dp。我们发现一个序列的子序和与2 ^ (n - 1)与sum有关,若要子序和是m的倍数,分两种情况:1:2不是m的因子,那么容易发现2  ^ (n - 1)不会影响子序和是否是m的倍数。2:2是m的因子,但是m最大范围是5e3,所以最大有2 ^ 12这个因子,而所以当n大于12的时候又变成了情况1.所以,实际上dp的第二维的大小只有十几,复杂度降为了O(n * logn * m),但是这样的复杂度仍然不够优秀,我们考虑继续优化。我们可以发现,dp[i][j][k]中,随着j的增加,k那一维的模数也在不断减少,模数是m + m / 2 + m / 4 ...这个复杂度是O(m)的,所以我们逐步优化之后,复杂度降低到了O(n * m)。

代码:

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn = 5010;
const LL mod = 1000000007;
int a[maxn], dp[2][15][maxn], p[20];
void update(int &x, int y) {
x = ((long long)x + y) % mod;
}
int main() {
int n, m;
int ans = 0;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
int cnt = 0;
int tmp = m;
while(tmp % 2 == 0) {
tmp /= 2;
cnt++;
}
dp[0][0][0] = 1;
for (int i = 0; i < n; i++) {
memset(dp[(i + 1) & 1], 0, sizeof(dp[(i + 1) & 1]));
for (int j = 0; j <= cnt + 1; j++) {
memset(dp[(i + 1) & 1][j], 0, sizeof(int) * (m / (1 << max(0, j - 1))));
}
for (int j = 0; j <= cnt; j++) {
int mm = m / (1 << max(0, j - 1)), mmm = m / (1 << max(0, j));
for (int k = 0; k < mm; k++) {
if(!dp[i & 1][j][k]) continue;
update(dp[(i + 1) & 1][j][k], dp[i & 1][j][k]);
update(dp[(i + 1) & 1][j + 1][(k + a[i + 1]) % mmm], dp[i & 1][j][k]);
}
}
for (int j = 0; j < tmp; j++) {
if(!dp[i & 1][cnt + 1][j]) continue;
update(dp[(i + 1) & 1][cnt + 1][j], dp[i & 1][cnt + 1][j]);
update(dp[(i + 1) & 1][cnt + 1][(j + a[i + 1]) % tmp], dp[i & 1][cnt + 1][j]);
}
}
for (int i = 1; i <= cnt + 1; i++) {
update(ans, dp[n & 1][i][0]);
}
printf("%d\n", ans);
return 0;
}

  

Comet OJ - contest #3 C DP的更多相关文章

  1. Comet OJ - Contest #8

    Comet OJ - Contest #8 传送门 A.杀手皇后 签到. Code #include <bits/stdc++.h> using namespace std; typede ...

  2. Comet OJ - Contest #2 简要题解

    Comet OJ - Contest #2 简要题解 cometoj A 模拟,复杂度是对数级的. code B 易知\(p\in[l,r]\),且最终的利润关于\(p\)的表达式为\(\frac{( ...

  3. Comet OJ - Contest #2简要题解

    Comet OJ - Contest #2简要题解 前言: 我没有小裙子,我太菜了. A 因自过去而至的残响起舞 https://www.cometoj.com/contest/37/problem/ ...

  4. Comet OJ - Contest #4--前缀和

    原题:Comet OJ - Contest #4-B https://www.cometoj.com/contest/39/problem/B?problem_id=1577传送门 一开始就想着暴力打 ...

  5. Comet OJ - Contest #11 题解&赛后总结

    Solution of Comet OJ - Contest #11 A.eon -Problem designed by Starria- 在模 10 意义下,答案变为最大数的最低位(即原数数位的最 ...

  6. Comet OJ - Contest #13-C2

    Comet OJ - Contest #13-C2 C2-佛御石之钵 -不碎的意志-」(困难版) 又是一道并查集.最近做过的并查集的题貌似蛮多的. 思路 首先考虑,每次处理矩形只考虑从0变成1的点.这 ...

  7. Comet OJ - Contest #13 「火鼠的皮衣 -不焦躁的内心-」

    来源:Comet OJ - Contest #13 芝士相关: 复平面在信息学奥赛中的应用[雾 其实是道 sb 题??? 发现原式貌似十分可二项式定理,然后发现确实如此 我们把 \(a^i\) 替换成 ...

  8. Comet OJ - Contest #13 「佛御石之钵 -不碎的意志-」(hard)

    来源:Comet OJ - Contest #13 一眼并查集,然后发现这题 tmd 要卡常数的说卧槽... 发现这里又要用并查集跳过访问点,又要用并查集维护联通块,于是开俩并查集分别维护就好了 一开 ...

  9. Comet OJ - Contest #5

    Comet OJ - Contest #5 总有一天,我会拿掉给\(dyj\)的小裙子的. A 显然 \(ans = min(cnt_1/3,cnt_4/2,cnt5)\) B 我们可以感性理解一下, ...

随机推荐

  1. .Net编译环境x86,x64,anycpu的区别

    一.定义 x86: 将程序集编译为由兼容 x86 的 32 位公共语言运行库运行. x64: 将程序集编译为由支持 AMD64 或 EM64T 指令集的计算机上的 64 位公共语言运行库运行. any ...

  2. dotNET面试(二)

    值类型与引用类型 1.值类型和引用类型的区别? 值类型包括简单类型.结构体类型和枚举类型,引用类型包括自定义类.数组.接口.委托等. 赋值方式:将一个值类型变量赋给另一个值类型变量时,将复制包含的值. ...

  3. Java高频经典面试题(第一季)五:递归与迭代

    编程题:  有n步台阶, 一次只能上 1步 或 2步, 共有多少种走法? 递归 循环迭代 递归: package will01; import org.junit.Test; public class ...

  4. java--substring内存溢出问题

    public class SubStringDemo { //substring() /** * jdk6 当调用 substring() 方法时,创建了一个新的String对象,但是string的v ...

  5. [BOOKS]Big Data: Principles and best practices of scalable realtime data systems

  6. Dictonary(Python)(一)

    基本用法: .keys .values .items >>> D = dict(a=1,b=2,c=3) >>> D {'a': 1, 'b': 2, 'c': 3 ...

  7. 【和孩子一起学编程】 python笔记--第四天

    第十一章: 可变循环 newStars = int(input("how many stars do you want?")) for i in range(newStars): ...

  8. PHP curl_multi_init函数

    curl_multi_init — 返回一个新cURL批处理句柄 说明 resource curl_multi_init ( void ) 允许并行地处理批处理cURL句柄. 参数 此函数没有参数. ...

  9. SCP-Py-001

    项目编号:Py-001 项目等级:Euclid 特殊收容措施: Py-001必须被存储于基金会主站的网络硬盘中,并切断一切与互联网的连接. Py-001突破收容在网络上传播后,一旦在一台计算机上被下载 ...

  10. RealsenseD415/D435深度相机常用资料汇总

    1.Realsense SDK 2.0 Ubuntu 16.04 安装指导网址https://github.com/IntelRealSense/librealsense/blob/master/do ...