题目描述
题解
由于又是整除的题,我们便只能够从整除的特性上去考虑这一个问题了。
可以证明,一个数的因数不超过 n \sqrt n n 个,这意味着我们可以在因数上做文章。
设
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示前
i
i
i个数,放在第
j
j
j个位置的方案数。对于当前数的每一个因数
x
x
x,有:
f
[
i
]
[
x
]
+
=
f
[
i
−
1
]
[
x
−
1
]
f[i][x]+=f[i-1][x-1]
f[i][x]+=f[i−1][x−1]
由于
i
i
i和
i
−
1
i-1
i−1有关,我们可以使用滚动数组;由于
i
i
i和
i
−
1
i-1
i−1转移的时候如果不是因数要每一个状态都向
i
−
1
i-1
i−1转移,所以我们一定要使用滚动数组进行处理。
每次可以将因数排序,从大到小转移即可。
所以遇见 g c d gcd gcd的题就一定要想到分解质因数,遇到整除的题一定要想到分解因数。
时间复杂度: O ( n n ) . O(n\sqrt n). O(nn).
#include <bits/stdc++.h>
using namespace std;
const int N = 2000000;
int n, ans = 0, m = 0;
int a[N], f[N], b[N];
const int P = 1e9+7;
int main(void)
{
scanf("%d", &n);
for (int i=1;i<=n;++i)
scanf("%d", a+i);
f[0] = 1;
for (int i=1;i<=n;++i)
{
m = 0;
for (int j=1;j*j<=a[i];++j)
{
if (a[i] % j == 0)
b[++m] = j;
if (a[i] % j == 0 && j * j ^ a[i])
b[++m] = a[i]/j;
}
sort(b+1,b+m+1);
reverse(b+1,b+m+1);
for (int i=1;i<=m;++i)
f[b[i]] = (f[b[i]]+f[b[i]-1]) % P;
}
for (int i=1;i<=1e6;++i)
ans = (ans+f[i]) % P;
cout<<ans<<endl;
return 0;
}