Ⅰ . 朴 素 做 法 \color{Red}Ⅰ.朴素做法 Ⅰ.朴素做法
设 d p [ k ] 为 当 前 序 列 长 k 有 多 少 种 选 法 设dp[k]为当前序列长k有多少种选法 设dp[k]为当前序列长k有多少种选法
那 么 对 于 当 前 的 a i , 筛 选 a i 的 所 有 因 子 s 那么对于当前的a_i,筛选a_i的所有因子s 那么对于当前的ai,筛选ai的所有因子s
d p [ s ] + = d p [ s − 1 ] dp[s]+=dp[s-1] dp[s]+=dp[s−1]
但 是 这 样 直 接 转 移 d p 数 组 已 经 改 变 了 , 下 一 个 因 子 的 转 移 可 能 会 出 问 题 但是这样直接转移dp数组已经改变了,下一个因子的转移可能会出问题 但是这样直接转移dp数组已经改变了,下一个因子的转移可能会出问题
所 以 我 们 先 用 t e m p 数 组 和 n u m 数 组 保 存 本 次 加 多 少 , 再 一 起 加 上 去 所以我们先用temp数组和num数组保存本次加多少,再一起加上去 所以我们先用temp数组和num数组保存本次加多少,再一起加上去
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=1000009;
ll n,a[maxn],dp[maxn];
ll temp[maxn],num[maxn],top;
int main()
{
cin >> n;
for(int i=1;i<=n;i++) cin >> a[i];
dp[0]=1;
for(int i=1;i<=n;i++)
{
top=0;
for(int j=1;j<=sqrt( a[i] );j++)
{
if( a[i] % j != 0) continue;
temp[++top]=dp[j-1],num[top]=j;
if( j*j != a[i] ) temp[++top]=dp[ a[i]/j-1],num[top]=a[i]/j;
}
for(int j=1;j<=top;j++)
{
int x=num[j];
dp[x]=( dp[x]+temp[j] )%mod;
}
}
ll ans=0;
for(int i=1;i<=n;i++)
ans = ( ans+dp[i] )%mod;
cout << ans;
}
Ⅱ . 因 子 筛 \color{blue}Ⅱ.因子筛 Ⅱ.因子筛
前 面 用 额 外 数 组 来 辅 助 转 移 前面用额外数组来辅助转移 前面用额外数组来辅助转移
实 际 上 我 们 可 以 先 从 大 的 因 子 转 移 , 再 转 移 到 小 的 因 子 实际上我们可以先从大的因子转移,再转移到小的因子 实际上我们可以先从大的因子转移,再转移到小的因子
这 样 类 似 01 背 包 的 倒 序 转 移 就 不 会 影 响 这样类似01背包的倒序转移就不会影响 这样类似01背包的倒序转移就不会影响
但 是 如 何 获 得 从 大 到 小 的 所 有 因 子 呢 ? 但是如何获得从大到小的所有因子呢? 但是如何获得从大到小的所有因子呢?
因 为 n = 100000 , 所 以 直 接 使 用 因 子 筛 因为n=100000,所以直接使用因子筛 因为n=100000,所以直接使用因子筛
void init()//预先处理因子
{
for(int i=1;i<=MAXN*10;i++)
{
for(int j=i;j<=MAXN*10;j+=i)
{
p[j].push_back(i);
}
}
}
然 后 转 移 的 时 候 直 接 从 大 因 子 开 始 转 移 即 可 然后转移的时候直接从大因子开始转移即可 然后转移的时候直接从大因子开始转移即可