51Nod-1259-整数划分 V2

51Nod-1259-整数划分 V2

将N分为若干个整数的和,有多少种不同的划分方式,例如:n = 4,{4} {1,3} {2,2} {1,1,2} {1,1,1,1},共5种。由于数据较大,输出Mod 10^9 + 7的结果即可。

Input

输入1个数N(1 <= N <= 50000)。

Output

输出划分的数量Mod 10^9 + 7。

Input示例

4

Output示例

5

题解

分块DP
复杂度O(n*sqrt(n))

设m = sqrt(n)

我们可以先考虑使用1~m凑成数的方案, 完全背包即可

对于剩下的m+1 ~ n 我们发现每个数最多使用 m 次
然后
g[i][j] 表示使用了i个数(m+1~m+i)和为j的方案数
令m++
g[i][j] = g[i-1][j-m] + g[i][j-i]
这什么意思呢?
对于一个序列,我们有两种操作:
1.添加一个基数m
2.给每个数+1(注意这里的j是正着枚举的,所以可重复给每个数加一)

Code

#include<bits/stdc++.h>
#define LL long long
#define RG register
using namespace std;

inline int gi() {
    int f = 1, s = 0;
    char c = getchar();
    while (c != '-' && (c < '0' || c > '9')) c = getchar();
    if (c == '-') f = -1, c = getchar();
    while (c >= '0' && c <= '9') s = s*10+c-'0', c = getchar();
    return f == 1 ? s : -s;
}
const int N = 50010, Mod = 1e9+7;
int f[N], g[250][N], s[N];
int main() {
    //freopen(".in", "r", stdin);
    //freopen(".out", "w", stdout);
	int n = gi(), m = sqrt(n)+1;
	f[0] = 1;
	for (int i = 1; i < m; i++)
		for (int j = i; j <= n; j++)
			(f[j] += f[j-i]) %= Mod;
	int ans = 0;
	g[0][0] = 1;
	s[0] = 1;
	for (int i = 1; i < m; i++) {
		for (int j = m; j <= n; j++) {
			g[i][j] = (g[i-1][j-m] + g[i][j-i]) % Mod;
			s[j] = (s[j] + g[i][j]) % Mod;
		}
	}
	for (int i = 0; i <= n; i++)
		ans = (ans + (LL)f[i]*s[n-i]%Mod) % Mod;
	printf("%lld
", ans);
    return 0;
}

原文地址:https://www.cnblogs.com/zzy2005/p/9890404.html