题目
C. Multiplicity
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
You are given an integer array a1,a2,…,ana1,a2,…,an.
The array bb is called to be a subsequence of aa if it is possible to remove some elements from aa to get bb.
Array b1,b2,…,bkb1,b2,…,bk is called to be good if it is not empty and for every ii (1≤i≤k1≤i≤k) bibi is divisible by ii.
Find the number of good subsequences in aa modulo 109+7109+7.
Two subsequences are considered different if index sets of numbers included in them are different. That is, the values of the elements do not matter in the comparison of subsequences. In particular, the array aa has exactly 2n−12n−1 different subsequences (excluding an empty subsequence).
Input
The first line contains an integer nn (1≤n≤1000001≤n≤100000) — the length of the array aa.
The next line contains integers a1,a2,…,ana1,a2,…,an (1≤ai≤1061≤ai≤106).
Output
Print exactly one integer — the number of good subsequences taken modulo 109+7109+7.
Examples
input
Copy
2 1 2
output
Copy
3
input
Copy
5 2 2 1 22 14
output
Copy
13
Note
In the first example, all three non-empty possible subsequences are good: {1}{1}, {1,2}{1,2}, {2}{2}
In the second example, the possible good subsequences are: {2}{2}, {2,2}{2,2}, {2,22}{2,22}, {2,14}{2,14}, {2}{2}, {2,22}{2,22}, {2,14}{2,14}, {1}{1}, {1,22}{1,22}, {1,14}{1,14}, {22}{22}, {22,14}{22,14}, {14}{14}.
Note, that some subsequences are listed more than once, since they occur in the original array multiple times.
思路 计数dp
有条件的计数背包,\(dp[i][j]\)表示考虑前i个物品,当背包容量为j时的方案数为多少
显然
\(\begin{equation} dp[i][j]=\left\{ \begin{aligned} dp[i - 1][j],\quad a[i] != a[j]\\ dp[i - 1][j - 1] + dp[i - 1][j],\quad a[i] \bmod j = 0\\ \end{aligned} \right . \end{equation}\)
当然\(dp[i][j]\)可以换成一维的滚动数组,然后从倒序更新
暴力的话,\(O(n^2)\)很容易超时,观察上述等式,当且仅当\(j \mid a_i\)时,\(dp[j]\)(滚动数组)才会被更新,否则其和上一层相等,所以我们每次只更新因子,其余的不用更新,所以遍历\(1到\sqrt{n}\),把因子放进去,然后每次只遍历因子
复杂度\(O(n\sqrt{n})\)
Code
/* CodeForces-1061C */
#include <iostream>
#include <numeric>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 1e6 + 10, mod = 1e9 + 7;
// 计数类背包
// dp[i][j] 表示从前i个数 抽取大小为j的数的个数
// | dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1] if (j | a[i])整除
// | dp[i][j] = dp[i - 1][j]
// dp[1][0] = 1
// 滚动数组
// dp[j] = dp[j] + dp[j - 1];
int a[N];
long long dp[N];
long long add(long long a, long long b) {
return (a % mod + b % mod) % mod;
}
int main() {
int n; cin >> n;
dp[0] = 1;
for(int i = 1; i <= n; i ++) {
cin >> a[i];
vector<int> curr;
for (int j = 1; j <= a[i] / j; j ++) {
if (a[i] % j == 0) {
curr.push_back(j);
if (a[i] / j != j)
curr.push_back(a[i] / j);
}
}
sort(curr.begin(), curr.end(), greater<int>());
for (auto &x: curr) {
dp[x] = add(dp[x], dp[x - 1]);
}
}
long long ans = 0;
for (int i = 1; i <= n; i ++) ans = add(ans, dp[i]);
cout << ans;
}