思路:
dp[i][j][k]表示满足前i个数,和为j,lcm为k的数目。
设a为解的第i+1个数。
那么状态转移就为
dp[i+1][j+a][lcm(a,k)]+=dp[i][j][k]。
但是由于三维开不了,所以用滚动数组。
代码如下:
1 #include<iostream> 2 #include<stdio.h> 3 #include<algorithm> 4 #include<iomanip> 5 #include<cmath> 6 #include<cstring> 7 #include<vector> 8 #define ll __int64 9 #define pi acos(-1.0) 10 #define MAX 1001 11 #define M 1000000007 12 using namespace std; 13 int num[MAX],LCM[MAX][MAX],dp[2][MAX][MAX],cnt; 14 int gcd(int a,int b) 15 { 16 while(b){ 17 int t=a; 18 a=b; 19 b=t%b; 20 } 21 return a; 22 } 23 int lcm(int a,int b) 24 { 25 return a/gcd(a,b)*b; 26 } 27 void init()//预处理出lcm 28 { 29 int i,j; 30 for(i=1;i<MAX;i++){ 31 LCM[i][i]=i; 32 for(j=1;j<i;j++) 33 LCM[j][i]=LCM[i][j]=lcm(i,j); 34 } 35 } 36 int main(){ 37 int t,n,m,k,i,j,now,v; 38 init(); 39 while(scanf("%d%d%d",&n,&m,&k)!=EOF){ 40 cnt=0; 41 for(i=1;i<=m;i++) 42 if(m%i==0) 43 num[cnt++]=i; 44 now=0; 45 for(i=0;i<=n;i++)//不要用memset 46 for(j=0;j<cnt;j++) 47 dp[now][i][num[j]]=0; 48 dp[now][0][1]=1; 49 for(t=1;t<=k;t++){ 50 now^=1; 51 for(i=0;i<=n;i++)//不要用memset 52 for(j=0;j<cnt;j++) 53 dp[now][i][num[j]]=0; 54 for(i=t-1;i<=n;i++){ 55 for(j=0;j<cnt;j++){ 56 if(dp[now^1][i][num[j]]==0) continue; 57 for(v=0;v<cnt;v++){ 58 int s=i+num[v]; 59 int l=LCM[num[j]][num[v]]; 60 if(s>n||m%l!=0) continue; 61 dp[now][s][l]+=dp[now^1][i][num[j]]; 62 dp[now][s][l]%=M; 63 } 64 } 65 } 66 } 67 printf("%d ",dp[now][n][m]); 68 } 69 return 0; 70 }