1213 - Sum of Different Primes(DP)

来源:互联网 发布:淄博seo推广优化 编辑:程序博客网 时间:2024/06/02 08:26

该题是数学和DP的结合,其实递推法本身就很像DP ,且数学和DP都是很灵活的东西 。

我在一开始想暴搜一下,找找规律(估计会超时),结果样例都跑不出来,也没看出小数据有什么规律,于是想到了DP,一开始应该就推对了,只是样例都不对,后来看别人的代码,发现素数的总和要从大到小枚举。  我们用d[i][j]表示j个素数相加为i的情况数 。   如果将i从小到大枚举,会出现重复枚举的情况,比如2,3和3,2都计算了一遍。  如果正着来,d[2][1] = 1;d[3][1] = 1; 然后在计算d[5][2]的时候就会将二者都算进来,相当于恰好重复算了一次,之所以会这样,和j的顺序没有关系,都是因为i,在枚举2这个素数时,d[5][2]加了一遍,在枚举3使又加了一遍。但是如果倒着枚举,就恰好会只加一次,也就是说恰好让当前枚举的素数错过,使得没有任何重复的情况出现。

细节参见代码:

#include<bits/stdc++.h>using namespace std;typedef long long ll;const int INF = 1000000000;const int maxn = 1200;int T,n,m,k,p,vis[maxn+5]={0},prime[maxn+5],cnt = 0;ll d[maxn][20]={0};ll ans = 0;void init() {    int m = sqrt(maxn+0.5);    for(int i=2;i<=m;i++) if(!vis[i])        for(int j=i*i;j<=maxn;j+=i) vis[j] = 1;    for(int i=2;i<=maxn;i++)        if(!vis[i]) prime[cnt++] = i;}void dp() {    d[0][0] = 1;    for(int i=0;i<cnt;i++) {        int w = prime[i];        for(int j=1120;j>=w;j--) {            for(int k=1;k<=14;k++) {                d[j][k] += d[j-w][k-1];            }        }    }}int main() {    init();  dp();    while(~scanf("%d%d",&n,&p)) {        if(!n && !p) break;        printf("%lld\n",d[n][p]);    }    return 0;}

0 0
原创粉丝点击