单调性 - 51Nod 1383(整数分解为2的幂), 2019.10.25 T1

题面

51Nod 1383

解法 1

\(n\) 的划分数为 \(f(n)\) , 则
\[f(n)= \begin{cases} 1 & n=1\\ f(n-1) & n\equiv 1\pmod{2}, n\ne 1 \\ f(n-1)+f(\lfloor n/2\rfloor) & n\equiv 0\pmod{2} \end{cases}\]

证明略. 时间复杂度 \(O(n)\), 空间复杂度 \(O(n)\). 测评时耗时 \(3.502647\ \text{ms}\), 占用 \(3952\ \text{KiB}\).

程序

#include <iostream>
#include <cstring>
using namespace std;

#define MAXN 1000050
#define MOD 1000000007
int d[MAXN];

void calcdp(int m) {
    d[1] = 1;
    for (int i = 2; i <= m; i++)
        if (i % 2)
            d[i] = d[i - 1];
        else
            d[i] = (d[i - 1] + d[i / 2]) % MOD;
}

int main() {
    int m;
    cin >> m;
    calcdp(m);
    cout << d[m] << endl;
    return 0;
}

解法 2

考虑枚举法. 为了保证正确性(不重), 可以采用加入单调性的方法.

\(n\) 的划分中最小的不小于 \(2^i\) 的划分数为 \(f(n,i)\) , 则
\[ f(n, i)= \begin{cases} \sum_{2^j< n}f(n-2^j,j)&n>1\\ 1&n=1 \end{cases} \]

时间复杂度为 \(O(n\log^2n)\) , 空间复杂度 \(O(n\log{n})\). 可保证40分. \(n=10^6\) 时耗时约 \(3\ \text{s}\).

观察题目所给样例, \(7\) 的划分中没有以 \(2\) 及以上开头的. 这是因为 \(2\nmid 7\). 于是可以有
\[ f(n, i)= \begin{cases} 0&2^i\nmid n\\ \sum_{2^j< n}f(n-2^j,j)&n>1\\ f(n, i)=1&n=1 \end{cases} \]
从上至下呈覆盖关系.

程序

#include <iostream>
#include <cstring>
using namespace std;

#define MAXN 1000050
#define LG_MAXN 24
#define MOD 1000000007
int d[MAXN][LG_MAXN];

int dp(int m, int n) {
    if (d[m][n] > -1) return d[m][n];
    if (m % (1 << n)) return d[m][n] = 0; // (*)
    if (m <= 1) return d[m][n] = 1;
    int ans = 0;
    for (int i = n; (1 << i) <= m; i++) {
        ans += dp(m - (1 << i), i);
        ans %= MOD;
    }
    return d[m][n] = ans;
}

void calcdp(int m) {
    memset(d, -1, sizeof(d));
    for (int i = 1; i <= m; i += 1000)
        dp(i, 0);
    dp(m, 0);
}

int main() {
    int m;
    cin >> m;
    calcdp(m);
    cout << d[m][0] << endl;
    return 0;
}

为了避免栈溢出, 可以采用分段计算的方法. 测评时耗时 \(312.835601\ \text{ms}\), 占用 \(93860\ \text{KiB}\).

猜你喜欢

转载自www.cnblogs.com/lrw04/p/11795016.html