Multiplicity

题解

\(dp[i][j]\):用了\(i\)个数序号是\(j\)的方案数。

\[dp[i][j] = \begin{cases} dp[i - 1][j] + dp[i - 1][j - 1] & (a[i] \% j == 0)\\ dp[i - 1][j] \\ \end{cases} \]

因为\(dp[i][j]\)只和\(i - 1\)的状态有关,所以可以用滚动数组优化。另外,观察发现,\(dp[i][j]\)的更新当且仅当\(a[i] \% j == 0\),预处理\(a[i]\)的约数,在用背包的优化思路,可以做到\(O(nsqrt(max(a_i)))\)

代码

#include <bits/stdc++.h>
using namespace std;

const int N = 100005;
const int mod = 1000000007;

int n;
int a[N], cnt[N * 10];

int main()
{
    cin >> n;
    for (int i = 1; i <= n; ++i) cin >> a[i];

    cnt[0] = 1;
    for (int i = 1; i <= n; ++i) {
        vector<int> t;
        for (int j = 1; j * j <= a[i]; ++j) if (a[i] % j == 0) {
            t.push_back(j);
            if (a[i] != j * j) t.push_back(a[i] / j);
        }
        sort(t.begin(), t.end());
        reverse(t.begin(), t.end());
        for (auto &it: t) {
            cnt[it] += cnt[it- 1];
            cnt[it] %= mod;
        }
    }

    int ans = 0;
    for (int i = 1; i <= n; ++i) {
        ans += cnt[i];
        ans %= mod;
    }
    cout << ans;

    return 0;
}
posted @ 2018-11-30 00:13  天之道,利而不害  阅读(392)  评论(0)    收藏  举报