您的位置:首页 > Web前端

1213 - Sum of Different Primes(DP)

2015-09-05 13:17 423 查看
该题是数学和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
[p]);
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: