这里,若干两两不同的质数之和,这里其实很容易想到首先我们要求出2019内的所有质数,这个打个表就好了,其次两两不同,我们应该要想到动态规划。
这里设dp[i][j]表示前i个质数,可以两两不同加起来等于j的方案数。
如果当前j>=prime[i],说明当前的质数可以取,取完后我们只要看j-prime[i]有多少种取法,那么方案数之中有部分为dp[i-1][j-prime[i]]种,另外一部分是不取当前的质数prime[i],即dp[i-1][j]。若j<prime[i],说明当前我们取不了prime[i],只有上面两种情况下的后一种即dp[i-1][j]。
其次,我们怎么初始化呢?我们初始化dp[0][0]=1,这样我们就能在第一次质数2的时候初始化了。
具体代码如下所示:
#include <iostream>
using namespace std;
#define N 2020
int prime[N];//质数表
int fg[N];
int cnt=0;
long long dp[N][N];
//挑选出小于等于2019的质数
void init()
{
for(int i=2;i<=2019;i++)
{
if(!fg[i])
{
prime[++cnt]=i;
for(int j=2;j*i<=2019;j++)
{
fg[j*i]=1;
}
}
}
}
int main()
{
// 请在此输入您的代码
init();
dp[0][0]=1;
for(int i=1;i<=cnt;++i)
{
for(int j=0;j<=2019;++j)
{
//j<prime[i] 相当于当前最后一个质数取不了 相当于只能用前i-1个
//j>=prime[j] 除了dp[i-1][j]可以取到j
//还能看dp[i-1][j-prime[i]]有多少种情况 这是算上了第i个质数的情况
dp[i][j]=dp[i-1][j];
if(j>=prime[i])
{
dp[i][j]=dp[i-1][j]+dp[i-1][j-prime[i]];
}
}
}
cout<<dp[cnt][2019];
// cout<<"55965365465060";
return 0;
}
当然,我们还能减小空间复杂度,即滚动数组啥的,将main中的dp改成下面这种形式:
dp[0]=1;
for(int i=1;i<=cnt;i++)
{
for(int j=2019;j>=prime[i];j--)
{
dp[j]=dp[j]+dp[j-prime[i]];//相当于dp[i-1][j]+dp[i-1][j-prime[i]]
}
}