hdu-4345-Permutation - DP+数学或记忆化搜索

来源:互联网 发布:打电话软件 编辑:程序博客网 时间:2024/05/17 22:24

http://acm.hdu.edu.cn/showproblem.php?pid=4345

题意化简后:

给你一个n,要求选若干个数,使得他们的和小于等于N,然后他们的最小公倍数为一种合法方案,求有多少种合法方案。


首先一个情况,如果这些数不是互质的,那么一定可以找到一个方案,所有的数互质,并且最小公倍数等于当前方案,所以我们优先选互质的方案。


那么显然就是 选一个 小于等于N的所有质数  的幂次方 的集合

如 2 3 5 7 ...X(《N)

记忆化搜索或直接DP+打表


dp[i][j] 表示前i个素数,构成和为j(j<=N)的方案
dp[i][j]=dp[i-1][j-peime[i+1]^k]  +dp[i-1][j];   //表示选了 prime[i+1]^k 到当前方案


三层for。。直接本地跑答案 然后打表交即可

#include <cstdio>#include <cmath>#include <cstring>#include <string>#include <algorithm>#include <queue>#include <map>#include <set>#include <vector>#include <iostream>using namespace std;const double pi=acos(-1.0);double eps=0.000001;long long gcd(long long a,long long b){    if (!b)return a;    return  gcd(b,a%b);}long long n,q;bool f[2005];long long prime[1105];long long id=0;long long dp[1005][1005];//dp[i][j] 表示前i个素数,构成和为j(j<=N)的方案//dp[i][j]=dp[i-1][j-k*peime[j-1]]    //  +dp[i-1][j];long long ans[1005]  ={答案太长不贴出来};int main(){    /*    long long i,j,k;    f[1]=true;    for (i=2;i<=1100;i++)    {        if (f[i]==false)            for (j=i*i;j<=1100;j+=i)            f[j]=true;    }    for (i=2;i<=1100;i++)        if (f[i]==false)        prime[++id]=i;long long cnt=1; while(1)//scanf("%d",&n)!=EOF) {     if (cnt==1001)break;     n=cnt++;     memset(dp,0,sizeof(dp));     dp[0][0]=1;    for (i=0;i<=id-1;i++)    {        if (prime[i+1]>n)break;        for (j=0;j<=n;j++)        {            if (!dp[i][j]) continue;            long long tmp=prime[i+1];            dp[i+1][j]+=dp[i][j];  //不选i            for (k=0;;k++)            {                if (tmp+j>n)break;                dp[i+1][j+tmp]+=dp[i][j];                tmp*=prime[i+1];            }        }    }    long long end=i;    long long sum=0;    for (i=1;i<=n;i++)        sum+=dp[end][i];    ans[n]=sum+1; } /*freopen("out.txt","w",stdout); for (i=1;i<=1000;i++)    printf("%lld,",ans[i]); */ while(scanf("%lld",&n)!=EOF){    printf("%lld\n",ans[n]);}    return 0;}


0 0
原创粉丝点击