dp[i][j][k] i为K位的最小公倍数 j为k位的和 k以滚动数组的形式
这题最棒的是 有一个强有力的剪枝 组成公倍数m的肯定都是M的质因子 这样1000里面最多就30多个 复杂度可过了
1 #include <iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<stdlib.h> 6 #include<queue> 7 using namespace std; 8 #define mod 1000000007 9 int dp[1010][1010][2]; 10 int q[110][1010],f[1010],lc[1010][1010]; 11 int p[1010]; 12 int gcd(int a,int b) 13 { 14 return b==0?a:gcd(b,a%b); 15 } 16 int main() 17 { 18 int n,m,k,i,j,g; 19 for(i = 1 ; i <= 1000 ; i++) 20 for(j = 1; j <= 1000 ; j++) 21 lc[i][j] = i*j/gcd(i,j); 22 while(scanf("%d%d%d",&n,&m,&k)!=EOF) 23 { 24 int o; 25 int to = 0; 26 for(i =1; i <= m ; i++) 27 if(m%i==0) 28 { 29 to++; 30 p[to] = i; 31 } 32 memset(dp,0,sizeof(dp)); 33 for(i = 1 ; i <= min(n,m) ; i++) 34 { 35 dp[i][i][1] = 1; 36 } 37 for(i = 2; i <= k; i++) 38 { 39 for(o = 1; o <= to ; o++) 40 for(g = 1; g <= n ; g++) 41 dp[p[o]][g][i%2] = 0; 42 for(j = 1 ; j <= to ; j++) 43 { 44 for(g = i-1; g <= n ; g++) 45 { 46 if(dp[p[j]][g][(i-1)%2]==0) 47 continue; 48 for(o = 1 ; o <= to ; o++) 49 { 50 int x = lc[p[j]][p[o]]; 51 if(g+p[o]>n) 52 break; 53 if(x>m) 54 continue; 55 dp[x][g+p[o]][i%2] = (dp[x][g+p[o]][i%2]+dp[p[j]][g][(i-1)%2])%mod; 56 } 57 } 58 } 59 } 60 printf("%d ",dp[m][n][k%2]); 61 } 62 return 0; 63 }