P9425 [蓝桥杯 2022 国 B] 2022

一、题目描述

\(2022\) 拆分成 \(10\)互不相同正整数之和,有多少种方案?

二、问题简析

\(dp[i][j]=\) \(i\)\(j\) 划分的方案数(满足互不相同正整数)。有两种实现方式:

  • \(dp[i][j]\) 不含 \(1\)
    \(dp[i-j][j]\) 的基础上,每个元素 +1。有 \(j\) 个元素,每个元素 +1,即 \((i-j)+1\times j=i\)
  • \(dp[i][j]\)\(1\)
    我们要找到一个不含 \(1\)dp,且划分为 \(j-1\),在它的基础上添加元素 \(1\)。首先,\(i\) 中拿出一个 \(1\),变成 \(i-1\)。仿照上例,在一个 dp 的基础上,每个元素都 +1,就得到了不含 \(1\)dp。由 \((i-1)-1\times (j-1)=i-j\),得到 \(dp[i-j][j-1]\)

综上所述,\(dp[i][j]=dp[i-j][j]+dp[i-j][j-1]\)

三、代码

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

int n, k;
ll dp[2030][15]; // dp[i][j] -- i的j划分 

int main()
{
	#ifdef LOCAL
	freopen("test.in", "r", stdin);
	#endif
	
	cin >> n >> k;
	
	// 边界条件一:dp[0][1,2,...]=0
	// ...                             // 不允许0存在,所以0的所有划分都为0 
	
	// 边界条件二:dp[1,2,...][1]=1 
	for (int i = 1; i <= n; ++i)       // i的1划分,即自身 
		dp[i][1] = 1;
	
	for (int i = 1; i <= n; ++i)       // i=0已经在条件一中初始化 
	{
		for (int j = 2; j <= k; ++j)   // j=1已经在条件二中初始化 
		{
			if (i >= j)
				dp[i][j] = dp[i - j][j] + dp[i - j][j - 1];
			// if i < j, dp[i][j] = 0 (因为不能有0存在)
		}
	}
	
	cout << dp[n][k] << endl;
	
	return 0;
}

posted @ 2024-05-13 11:43  ltign  阅读(14)  评论(0编辑  收藏  举报