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; }