【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计数 ...
随机推荐
- "api-ms-win-crt-runtime-l1-1-0.dll 丢失"怎么办?详细解决步骤
api-ms-win-crt-runtime-l1-1-0.dll 丢失 电脑找不到api-ms-win-crt-runtime-l1-1-0.dll文件解决方法: 问题描述: 1.开机提示" ...
- c++文件对齐
头文件#include <iomanip> 关键词:setw(n),std::left,std::right 实例:输出一个0-4的12*12方阵,要求数字宽度为4,居左对齐,右下角输出出 ...
- 笔试题——C++开发简单记录错误模块
题目:链接:https://www.nowcoder.com/questionTerminal/67df1d7889cf4c529576383c2e647c48 来源:牛客网 解析及代码来源:http ...
- last命令详解
基础命令学习目录首页 原文链接:https://blog.csdn.net/jerry_1126/article/details/54427119 [root@xiaoma /root] test!# ...
- HTML常用头部变量
简例:访问baidu的头部 GET /?tn=98827400_hao_pg HTTP/1.1 Host: www.baidu.com Connection: keep-alive Cache-Con ...
- 《Spring1之第五次站立会议》
<第五次站立会议> 昨天:试着做了一下主框架里的在线人数的显示代码: 今天:向小伙伴们请教了我代码的错误的解决方法以及对TCP/IP协议进行了相关的了解. 遇到的问题:虽然基本原理不难理解 ...
- 谈对“Git”的认识与理解
自诞生于2005年以来,Git日臻完善,在高度易用的同时,仍然保留着初期设定的目标.它的速度飞快,及其适合管理大项目,它还有着令人难以置信的非线性分支管理系统,可以应付各种复杂的项目开发需求.接着说说 ...
- 团队作业7——第二次项目冲刺(Beta版本12.04——12.07)
1.当天站立式会议照片 本次会议在5号公寓3楼召开,本次会议内容:①:熟悉每个人想做的模块.②:根据项目要求还没做的完成. 2.每个人的工作 经过会议讨论后确定了每个人的分工 组员 任务 陈福鹏 实现 ...
- Mysql中实现递归查询
1.常规表字段 id,pid,lev,name 2.sql语句 DELIMITER // DROP PROCEDURE IF EXISTS Pro_GetColumnOrg//CREATE PROCE ...
- 汇编语言段和RSEG用法
RSEG是段选择指令,要想明白它的意思就要了解段的意思.段是程序代码或数据对象的存储单位.程序代码放到代码段,数据对象放到数据段.段分两种,一是绝对段,一是再定位段.绝对段在汇编语言中指定,在用L51 ...