洛谷 - P2563 质数和分解 【dp / 记忆化搜索】

题目描述

任何大于 1 的自然数 n 都可以写成若干个大于等于 2 且小于等于 n 的质数之和表达式(包括只有一个数构成的和表达式的情况),并且可能有不止一种质数和的形式。例如,9 的质数和表达式就有四种本质不同的形式:

9 = 2 + 5 + 2 = 2 + 3 + 2 + 2 = 3 + 3 + 3 = 2 + 7 。

这里所谓两个本质相同的表达式是指可以通过交换其中一个表达式中参加和运算的各个数的位置而直接得到另一个表达式。

试编程求解自然数 n 可以写成多少种本质不同的质数和表达式。

输入格式

文件中的每一行存放一个自然数 n(2 < n < 200) 。

输出格式

依次输出每一个自然数 n 的本质不同的质数和表达式的数目。

输入输出样例

输入 

2
200

输出 

1
9845164

解题思路

这题暴搜打卡可以过,但是太low了~~。

记忆化搜索我感觉应该可以,但是没写出来~

dp思路:

状态递推式: f[ i ] = \sum f(i-prim[ j ])   其中 prim[ j ] <= p,prim[ j ] 为素数

我刚开始写出了这个式子:

求 f[n]:

for(int i=1;i<=n;i++) {
	memset(vis,false,sizeof vis);
	for(int j=1;j<=tot && prim[j] <= i;j++) {
		int k = max(prim[j],i-prim[j])*100+min(prim[j],i-prim[j]);
		if(!vis[k]) {
			f[i] +=  f[i-prim[j]];
			vis[k] = true; 
		}		
	}
}

看起来贼nb,可惜不对, 把7分解为2 5 ,而5可分解为2 3,这样就是把7分解为了2 2 3; 把7分解为3 4,4又可以分解为2 2,这两种分解方法有重复。

then,正解:

memset(f,0,sizeof f);
f[0] = 1;
for(int i=1;i<=tot;i++) {
   for(int j=prim[i];j<=200;j++)
	f[j] += f[j-prim[i]];	 
}

这很像完全背包问题,把所有素数都看作体积为它本身的物品,就是问用这些物品,每个物品有无限个可用,装满容量为n的背包,有多少种装法。

初始化f[ 0 ]=1,即容量为0的背包有且只有不装这一种装法,

猜你喜欢

转载自blog.csdn.net/weixin_42765557/article/details/90215144