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\) 时:

\[f_{i,j}~=~f_{i - 1, j}
\]

否则:

\[f_{i,j}~=~f_{i - 1}{j}~+~f_{i - 1}{j - 1}
\]

考虑这个方程的状态是 \(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的更多相关文章

  1. # E. Mahmoud and Ehab and the xor-MST dp/数学+找规律+xor

    E. Mahmoud and Ehab and the xor-MST dp/数学/找规律 题意 给出一个完全图的阶数n(1e18),点由0---n-1编号,边的权则为编号间的异或,问最小生成树是多少 ...

  2. Codeforces Beta Round #2B(dp+数学)

    贡献了一列WA.. 数学很神奇啊 这个题的关键是怎么才能算尾0的个数 只能相乘 可以想一下所有一位数相乘 除0之外,只有2和5相乘才能得到0 当然那些本身带0的多位数 里面肯定含有多少尾0 就含有多少 ...

  3. zznu 1255 数字统计(数位DP, 数学方法)

    最近在学数位DP, 感觉还是满有收获的! 做了几个题之后想起来自己OJ上曾经做的一道题,以前是用数学方法写的,现在改用数位DP来写了一遍. 题目: 1255: 数字统计 时间限制: 1 Sec  内存 ...

  4. hdu4035 Maze 【期望dp + 数学】

    题目链接 BZOJ4035 题解 神题啊...orz 不过网上题解好难看,数学推导不写\(Latex\)怎么看..[Latex中毒晚期] 我们由题当然能很快写出\(dp\)方程 设\(f[i]\)表示 ...

  5. ZOJ3872 Beauty of Array---规律 | DP| 数学能力

    传送门ZOJ 3872 Beauty of Array Time Limit: 2 Seconds      Memory Limit: 65536 KB Edward has an array A  ...

  6. [CSP-S模拟测试]:题(DP+数学)

    题目描述 出个题就好了.这就是出题人没有写题目背景的原因.你在平面直角坐标系上.你一开始位于$(0,0)$.每次可以在上/下/左/右四个方向中选一个走一步.即:从$(x,y)$走到$(x,y+1),( ...

  7. [CSP-S模拟测试]:小奇的矩阵(matrix)(DP+数学)

    题目背景 小奇总是在数学课上思考奇怪的问题. 题目描述 给定一个$n\times m$的矩阵,矩阵中的每个元素$a_{i,j}$为正整数.接下来规定:    $1.$合法的路径初始从矩阵左上角出发,每 ...

  8. HDU 4599 Dice (概率DP+数学+快速幂)

    题意:给定三个表达式,问你求出最小的m1,m2,满足G(m1) >= F(n), G(m2) >= G(n). 析:这个题是一个概率DP,但是并没有那么简单,运算过程很麻烦. 先分析F(n ...

  9. HDU 4489 The King’s Ups and Downs (DP+数学计数)

    题意:给你n个身高高低不同的士兵.问你把他们按照波浪状排列(高低高或低高低)有多少方法数. 析:这是一个DP题是很明显的,因为你暴力的话,一定会超时,应该在第15个时,就过不去了,所以这是一个DP计数 ...

随机推荐

  1. excel窗口独立显示/单独显示

    天赋异禀的亲,一看就懂!

  2. shell之arp命令

    arp: 显示所有的表项. arp -d address: 删除一个arp表项. arp -s address hw_addr: 设置一个arp表项.   常用参数: -a 使用bsd形式输出.(没有 ...

  3. python基础_字符编码

    字符编码的历史 阶段一:现代计算机起源于美国,最早诞生也是基于英文考虑的ASCII 阶段二:为了满足中文,中国人定制了GBK 阶段三:各国有各国的标准,就会不可避免地出现冲突,结果就是,在多语言混合的 ...

  4. django_models_Meta字段详解

    Django模型类的Meta是一个内部类,它用于定义一些Django模型类的行为特性.而可用的选项大致包含以下几类 abstract 这个属性是定义当前的模型是不是一个抽象类.所谓抽象类是不会对应数据 ...

  5. “Hello World!”团队第六周第七次会议

    博客内容: 一.会议时间 二.会议地点 三.会议成员 四.会议内容 五.todo list 六.会议照片 七.燃尽图 八.checkout&push代码 一.会议时间 2017年11月23日  ...

  6. 特别好用的eclipse快捷键

    alt+/ 提示 alt+shift+r重命名 alt+shift+j添加文档注释 Ctrl+shift+y小写 Ctrl+shift+x大写 ctrl+shift+f格式化代码(需要取消输入法的简繁 ...

  7. alphe4

    队名:massivehard 组员1:(组长:晓辉) 今天完成了哪些任务: 服务器基本架设完毕 明日计划: 服务器与客户端对接 用户手写记录功能的完善 还剩下哪些计划: 用户手写记录功能 服务器与客户 ...

  8. [图的遍历&多标准] 1087. All Roads Lead to Rome (30)

    1087. All Roads Lead to Rome (30) Indeed there are many different tourist routes from our city to Ro ...

  9. Gradle入门(5):创建二进制发布版本

    在创建了一个实用的应用程序之后,我们可能想将其与他人分享.其中一种方式就是创建一个可以从网站上下载的二进制文件. 这篇教程描述了如何创建一个二进制发布版本,满足以下需求: 二进制发布一定不能使用所谓的 ...

  10. Java 文件下载功能 解决中文乱码

    Html部分 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <ti ...