【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计数 ...
随机推荐
- git ssh密钥配置添加
1. 初次安装git配置用户名和邮箱 $ git config --global user.name "xxx" $ git config --global user.email ...
- kali linux执行apt-get update失败(数字签名过期)
想要安装某个软件,执行apt-get update 失败,出现下面的错误: 自己查看了更新源是没有问题的,根据提示的错误google了一下,发现是数字签名过期了. 执行下面命令: apt-key ad ...
- nginx中location详解
Location block 的基本语法形式是: location [=|~|~*|^~|@] pattern { ... } [=|~|~*|^~|@] 被称作 location modifier ...
- excel中如何将时间戳转换为日期格式
https://www.cnblogs.com/xueluozhangxin/p/5868225.html =TEXT((B2/1000+8*3600)/86400+70*365+19,"y ...
- Ubuntu下开启mysql远程访问
1. 开启数据库3306端口 首先,使用如下指令查看3306端口是否对外开放. netstat -an | grep 3306 tcp 0 0 127.0.0.1:3306 0.0.0.0:* LIS ...
- 《找出1到正整数N中出现1的次数》
<找出1到正整数N中出现1的次数> 编程思想:依次求出正整数每个位数上出现1的次数,累加即可得到最后想要的结果:而每一位上出现1的个数与和它相邻的其它位数上的数字有关系(以此位置上的数为对 ...
- java读取properties文件的几种方法
一.项目中经常会需要读取配置文件(properties文件),因此读取方法总结如下: 1.通过java.util.Properties读取 Properties p=new Properties(); ...
- “吃神么,买神么”的第一个Sprint计划(第二天)
“吃神么,买神么”项目Sprint计划 ——5.22(第二天)立会内容与进度 团队组员各自任务: 冯美欣:logo的设计.搜索框的制作,"登陆/注册"的文字链接: 吴舒婷:导航条. ...
- visual stdio2013软件安装及单元测试
visual stdio2013软件安装及单元测试 一.visual stdio2013软件安装详解 今天,笔者为大家带来如何在Windows10下完美安装Visual Studio 2013专业版. ...
- Windows Apache(ApacheHaus)安装配置教程
1,Apache下载 选择一个版本,点击Download 点击File For Microsoft Windows 由于Apache HTTP Server官方不提供二进制(可执行)的发行版,所以我们 ...