【DP/数学】【CF1061C】 Multiplicity
Description
给定一个序列 ,求有多少非空序列 满足 是 的子序列并且 ,其中 是 的长度。答案对 取模
Input
第一行是序列 的长度
下面一行 个整数,代表序列
Output
输出一行一个整数代表答案
Hint
Solution
总觉得这题是假的= =
考虑DP。我们设 为考虑 中前 个数,填充到 中 个的方案数
方程显然:
当 时:
否则:
考虑这个方程的状态是 的,显然过不去,于是考虑优化:
我们发现能取到第二条转移方程当且仅当 是 的因数,而第一种第一种转移方程可以使用滚动数组直接省略掉。于是我们直接枚举 的因数,只在因数位置进行转移。同时注意因为 相同时的 时不能互相影响,所以对因数的转移要从大到小进行
考虑这么做的复杂度:
一共有 个数,每个数的因数是 ,同时排序需要 ,总复杂度 。
看起来根本过不去有木有= =
但是考虑因数个数事实上是一个很松的上界,经过实际测试, 范围内因数个数最多的数的因数不过 个,测试结果如下:
于是本题的实际复杂度为 ,其中
于是就可以轻松通过本题辣
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
一个数的因数个数是 是一个非常松的上界,事实上,在100万范围内因数个数最多的数的因数不过240个。遇到更大的范围可以 筛出所有数的因数来取得实际个数。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具