传送门
解析
这题的复杂度要求我们需要使用线性作法(废话)。
考虑dp,如果 (i|b[i]),则它是一种方案,反之亦然。
所以有这么一个方程:
[f_{i,j} = left{
egin{array}{lr}
f_{i,j} & , j
ot|a_i\
f_{i,j}+f_{i-1,j-1} & , j|a_i
end{array}
ight.
]
该dp的时间复杂度为 (O(nmax(a_i))) 的,显然过不去,需要优化。
我们发现能取到第二条转移方程当且仅当 (j) 是 (a_i) 的因数,而第一种第一种转移方程可以使用滚动数组直接省略掉。于是我们直接枚举 (a_i) 的因数,只在因数位置进行转移。同时注意因为 (i) 相同时的 (f) 时不能互相影响,所以对因数的转移要从大到小进行。好像01背包呀QAQ。
于是就可以轻松通过本题了。
#include<bits/stdc++.h>
namespace Bu_Yao_Tian_Tian_Bi_Sai {
using namespace std;
#define LL long long
inline LL read() {
char c=getchar();
LL sum=0;
while(c<'0'||c>'9') {
c=getchar();
}
while(c>='0'&&c<='9') {
sum=(sum<<3)-'0'+(sum<<1)+c,c=getchar();
}
return sum;
}
inline void write(LL x) {
if(x>9) {
write(x/10);
}
putchar(x%10+'0');
}
const int d[4][2]= {
{1,0},{0,1},{-1,0},{0,-1}
},mod=1e9+7,N=1e5+5;
}
using namespace Bu_Yao_Tian_Tian_Bi_Sai;
int a[N],dp[N];
vector<int> v[N];
inline void chai(int x) {
stack<int> sk;
int tmp=a[x];
for(int i=1; i*i<=tmp; i++) {
if(tmp%i) {
continue;
}
v[x].push_back(i);
if(i*i^tmp) {
sk.push(tmp/i);
}
}
while(sk.size()) {
v[x].push_back(sk.top()),sk.pop();
}
}
int main() {
int n=read();
for(int i=1; i<=n; i++) {
a[i]=read(),chai(i);
}
dp[0]=1;
for(int i=1; i<=n; i++) {
for(int j=v[i].size()-1; j>=0; j--) {
int tmp=v[i][j];
if(tmp<=n&&dp[tmp-1]) {
dp[tmp]=(dp[tmp]+dp[tmp-1])%mod;
}
}
}
int ans=0;
for(int i=1; i<=n; i++) {
ans=(ans+dp[i])%mod;
}
write(ans);
return 0;
}