Loading

【笔记】整数拆分与五边形数

广义五边形数 \(a_i = \dfrac{3n^2 \pm n}{2}\),前几项是 \(\{1,2,5,7,12,15,22,26,35,40,\cdots\}\)

我们记 \(f_i\)\(i\) 的划分数,有递推式 \(f_i = f_{i - 1} + f_{i - 2} - f_{i-5} - f_{i - 7} + f_{i + 12} \cdots\)

\(a\) 是平方级别增长的,所以递推项数是根号级别的,时间复杂度 \(\mathcal{O}(N\sqrt N)\)

#define N 500005
int n, f[N], g[N], t;
int main() {
	read(n, P);
	int x = 1;
	while(true){
		g[++t] = (x * x * 3 - x) / 2;
		g[++t] = (x * x * 3 + x) / 2;
		x++; if(g[t] > n)break;
	}
	if(g[--t] > n)t--;
	f[0] = 1;
	rp(i, n){
		rp(j, t){
			if(g[j] > i)break;
			if(((j + 1) / 2) & 1)ad(f[i], f[i - g[j]]);
			else su(f[i], f[i - g[j]]);
		}
	}
	printf("%d\n", f[n]);
	return 0;
}

如果拆分成若干个不相等的自然数之和怎么做?

我们可以将拆分写成一个上升序列,比如 \(A = \{1,2,4,5, 7\}\),等价于 \(B= \{b_i | b_i = \sum [a_j \ge i]\}\)

不难发现如果将 \(B\) 从小到大排序,相邻两项的差 \(\le 1\),所以我们只用考虑 \(1\sim \sqrt{N}\) 的数,做 \(\sqrt{N}\) 次完全背包即可,时间复杂度 \(\mathcal{O}(N\sqrt N)\)

#define N 500005
int n, f[N], g[N];
int main() {
	read(n);
	f[0] = g[0] = 1; int l = 0;
	for(int i = 1; i * (i + 1) / 2 <= n; i++){
		pre(j, n - i, l)f[j + i] = f[j];
		l += i; 
		rep(j, l, n){
			ad(g[j], f[j]);
			if(i + j <= n)ad(f[i + j], f[j]);
		}
	}
	printf("%d\n", g[n]);
	return 0;
}
posted @ 2022-05-11 19:37  7KByte  阅读(105)  评论(0编辑  收藏  举报