【DP/数学】【CF1061C】 Multiplicity
Description
给定一个序列 \(a\),求有多少非空序列 \(b\) 满足 \(b\) 是 \(a\) 的子序列并且 \(\forall~k~\in~[1,len_b],~~k \mid b_k\),其中 \(len_b\) 是 \(b\) 的长度。答案对 \(1e9+7\) 取模
Input
第一行是序列 \(a\) 的长度 \(n\)
下面一行 \(n\) 个整数,代表序列 \(a\)
Output
输出一行一个整数代表答案
Hint
\(1~\leq~n~\leq~100000~,~1~\leq~a_i~\leq~10^6\)
Solution
总觉得这题是假的= =
考虑DP。我们设 \(f_{i,j}\) 为考虑 \(a\) 中前 \(i\) 个数,填充到 \(b\) 中 \(j\) 个的方案数
方程显然:
当 \(j~\nmid~a_i\) 时:
\]
否则:
\]
考虑这个方程的状态是 \(O(n~\max(a_i))\) 的,显然过不去,于是考虑优化:
我们发现能取到第二条转移方程当且仅当 \(j\) 是 \(a_i\) 的因数,而第一种第一种转移方程可以使用滚动数组直接省略掉。于是我们直接枚举 \(a_i\) 的因数,只在因数位置进行转移。同时注意因为 \(i\) 相同时的 \(f\) 时不能互相影响,所以对因数的转移要从大到小进行
考虑这么做的复杂度:
一共有 \(n\) 个数,每个数的因数是 \(O(\sqrt{a_i})\),同时排序需要 \(O(\sqrt {a_i}~\times~\log (\sqrt{a_i}))\),总复杂度 \(O(n~\sqrt{a_i}~\log (\sqrt{a_i}))\)。
看起来根本过不去有木有= =
但是考虑因数个数事实上是一个很松的上界,经过实际测试,\([1,10^6]\) 范围内因数个数最多的数的因数不过 \(240\) 个,测试结果如下:

于是本题的实际复杂度为 \(\Theta(n~\times~d(a_i)~\log (d(a_i)))\),其中 \(d(a_i)~\leq~240\)
于是就可以轻松通过本题辣
Code
#include <cmath>
#include <cstdio>
#include <vector>
#include <algorithm>
#ifdef ONLINE_JUDGE
#define freopen(a, b, c)
#endif
#define rg register
#define ci const int
#define cl const long long
typedef long long int ll;
namespace IPT {
const int L = 1000000;
char buf[L], *front=buf, *end=buf;
char GetChar() {
if (front == end) {
end = buf + fread(front = buf, 1, L, stdin);
if (front == end) return -1;
}
return *(front++);
}
}
template <typename T>
inline void qr(T &x) {
rg char ch = IPT::GetChar(), lst = ' ';
while ((ch > '9') || (ch < '0')) lst = ch, ch=IPT::GetChar();
while ((ch >= '0') && (ch <= '9')) x = (x << 1) + (x << 3) + (ch ^ 48), ch = IPT::GetChar();
if (lst == '-') x = -x;
}
template <typename T>
inline void ReadDb(T &x) {
rg char ch = IPT::GetChar(), lst = ' ';
while ((ch > '9') || (ch < '0')) lst = ch, ch = IPT::GetChar();
while ((ch >= '0') && (ch <= '9')) x = x * 10 + (ch ^ 48), ch = IPT::GetChar();
if (ch == '.') {
ch = IPT::GetChar();
double base = 1;
while ((ch >= '0') && (ch <= '9')) x += (ch ^ 48) * ((base *= 0.1)), ch = IPT::GetChar();
}
if (lst == '-') x = -x;
}
namespace OPT {
char buf[120];
}
template <typename T>
inline void qw(T x, const char aft, const bool pt) {
if (x < 0) {x = -x, putchar('-');}
rg int top=0;
do {OPT::buf[++top] = x % 10 + '0';} while (x /= 10);
while (top) putchar(OPT::buf[top--]);
if (pt) putchar(aft);
}
const int maxn = 100010;
const int maxt = 1000010;
const int MOD = 1000000007;
int n;
int MU[maxn];
ll frog[maxt];
std::vector<int>p;
int main() {
freopen("1.in", "r", stdin);
qr(n);
for (rg int i = 1; i <= n; ++i) qr(MU[i]);
frog[0] = 1;
for (rg int i = 1; i <= n; ++i) {
p.clear();
for (rg int j = 1, sn = sqrt(MU[i]); j <= sn; ++j) if (!(MU[i] % j)) {
int k = MU[i] / j;
p.push_back(k);
if (k != j) p.push_back(j);
}
std::sort(p.begin(), p.end());
for (rg int j = p.size() - 1; ~j; --j) {
frog[p[j]] = (frog[p[j]] + frog[p[j] - 1]) % MOD;
}
}
ll ans = 0;
for (rg int i = 1; i <= n; ++i) ans = (ans + frog[i]) % MOD;
qw(ans, '\n', true);
return 0;
}
Summary
一个数的因数个数是 \(O(\sqrt{n})\) 是一个非常松的上界,事实上,在100万范围内因数个数最多的数的因数不过240个。遇到更大的范围可以 \(O(n \ln n)\) 筛出所有数的因数来取得实际个数。
【DP/数学】【CF1061C】 Multiplicity的更多相关文章
- # E. Mahmoud and Ehab and the xor-MST dp/数学+找规律+xor
E. Mahmoud and Ehab and the xor-MST dp/数学/找规律 题意 给出一个完全图的阶数n(1e18),点由0---n-1编号,边的权则为编号间的异或,问最小生成树是多少 ...
- Codeforces Beta Round #2B(dp+数学)
贡献了一列WA.. 数学很神奇啊 这个题的关键是怎么才能算尾0的个数 只能相乘 可以想一下所有一位数相乘 除0之外,只有2和5相乘才能得到0 当然那些本身带0的多位数 里面肯定含有多少尾0 就含有多少 ...
- zznu 1255 数字统计(数位DP, 数学方法)
最近在学数位DP, 感觉还是满有收获的! 做了几个题之后想起来自己OJ上曾经做的一道题,以前是用数学方法写的,现在改用数位DP来写了一遍. 题目: 1255: 数字统计 时间限制: 1 Sec 内存 ...
- hdu4035 Maze 【期望dp + 数学】
题目链接 BZOJ4035 题解 神题啊...orz 不过网上题解好难看,数学推导不写\(Latex\)怎么看..[Latex中毒晚期] 我们由题当然能很快写出\(dp\)方程 设\(f[i]\)表示 ...
- ZOJ3872 Beauty of Array---规律 | DP| 数学能力
传送门ZOJ 3872 Beauty of Array Time Limit: 2 Seconds Memory Limit: 65536 KB Edward has an array A ...
- [CSP-S模拟测试]:题(DP+数学)
题目描述 出个题就好了.这就是出题人没有写题目背景的原因.你在平面直角坐标系上.你一开始位于$(0,0)$.每次可以在上/下/左/右四个方向中选一个走一步.即:从$(x,y)$走到$(x,y+1),( ...
- [CSP-S模拟测试]:小奇的矩阵(matrix)(DP+数学)
题目背景 小奇总是在数学课上思考奇怪的问题. 题目描述 给定一个$n\times m$的矩阵,矩阵中的每个元素$a_{i,j}$为正整数.接下来规定: $1.$合法的路径初始从矩阵左上角出发,每 ...
- HDU 4599 Dice (概率DP+数学+快速幂)
题意:给定三个表达式,问你求出最小的m1,m2,满足G(m1) >= F(n), G(m2) >= G(n). 析:这个题是一个概率DP,但是并没有那么简单,运算过程很麻烦. 先分析F(n ...
- HDU 4489 The King’s Ups and Downs (DP+数学计数)
题意:给你n个身高高低不同的士兵.问你把他们按照波浪状排列(高低高或低高低)有多少方法数. 析:这是一个DP题是很明显的,因为你暴力的话,一定会超时,应该在第15个时,就过不去了,所以这是一个DP计数 ...
随机推荐
- 织梦调用多个栏目typeid="1,2,3"不支持的解决方法
织梦arclist调用副栏目不显示的解决办法: 打开/include/taglib/arclist.lib.php,代码约位于295-296行,查找以下两行代码: if($CrossID=='') $ ...
- Hands on Machine Learning with Sklearn and TensorFlow学习笔记——机器学习概览
一.什么是机器学习? 计算机程序利用经验E(训练数据)学习任务T(要做什么,即目标),性能是P(性能指标),如果针对任务T的性能P随着经验E不断增长,成为机器学习.[这是汤姆米切尔在1997年定义] ...
- NO.6:自学python之路------面向对象、内存持久化
引言 虽然加速学习了,可是还是感觉进度不够快,担心.还得准备毕业论文,真是焦虑. 正文 面向对象 编程是程序员用特定语法+数据结构+算法组成的代码,告诉计算机如何执行任务的过程.对不同的编程方式的特点 ...
- python 根据年月日,计算是这一年中的第几天
利用python计算某一天是这一年中的第几天,例如,给定年份= 2019年,月份= 1,日期= 3,则返回3:因为2019-01-03日期是2019年的第3 天. 首先,我们要知道闰年.平年怎么区分: ...
- Scrum立会报告+燃尽图(Final阶段第一次)
此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2480 项目地址:https://coding.net/u/wuyy694 ...
- 软件工程-东北师大站-第十一次作业(PSP)
PSP 饼状图 2.本周进度条 3.本周累计进度图 代码累计折线图 博文字数累计折线图
- Daily Scrum (2015/10/24)
由于这一天是周六,大家的学习热情依旧不是很高,但是在PM的要求和督促下,我们还是进行了一些工作.我们预计在明天(周日)完成全部的代码阅读工作,在下一周开始进行代码的编写工作,以下是我们的今日的工作情况 ...
- NABCD模型分析
1.N——need需求 目前,学习英语是所有学生会面临的问题.提高词汇量对学习英语是十分必要的,尤其是对大学生来说对手机的使用特别频繁,我们提高英语词汇量也应该把手机更好的利用起来,利用自己对手机的使 ...
- 人and绩效and职业道德
人行走在这个世界上 避免不了的是各种悲哀 人就像是一个茶几 上面放满了各种杯具 而要做的是要么把杯具打碎了咽下去,要么被杯具打晕 本布衣 躬耕于南阳 不求闻达于诸侯 每个人都可以选择自己的生活方式 或 ...
- Leetcode题库——35.搜索插入位置
@author: ZZQ @software: PyCharm @file: searchInsert.py @time: 2018/11/07 19:20 要求:给定一个排序数组和一个目标值,在数组 ...