【题意】
给定N,M,K:N、M<=1000,K<=100
求满足正数:
1. SUM (A1, A2, ..., Ai, Ai+1,..., AK) = N
2. LCM (A1, A2, ..., Ai, Ai+1,..., AK) = M
条件(A1, A2, ..., Ai, Ai+1,..., AK) 的方案数。
注意:(1,2)和(2,1)是两种方案。
【分析】
状态dp[k][i][j]表示考虑第k个数时,前面k个数的sum位i,lcm为j的方案数。
决策为枚举当前数。
最后答案为dp[K][N][M]
总复杂度为O(K*N*M*M),显然不行。
【优化】
考虑到每个数只能是M的因子,那么dp[k][i][j]表示sum为i,lcm为m的第j大的因子。枚举决策为m的因子。
总复杂度为O(K*N*30*30),最多有30个因子。
还可以使用滚动数组优化空间。
1 #include<stdio.h> 2 #include<math.h> 3 #include<string.h> 4 #define LL long long 5 #define MOD 1000000007 6 7 int gcd(int a,int b) 8 { 9 return b==0?a:gcd(b,a%b); 10 } 11 int lcm[1010][1010]; 12 int N,M,K; 13 int seq[33]; 14 int tot; 15 int hash[1010]; 16 void init() 17 { 18 19 tot = 0; 20 for (int i=1;i<=M;i++) 21 if (M % i == 0) 22 { 23 seq[++tot] = i; 24 hash[i] = tot; 25 } 26 return ; 27 } 28 29 30 31 LL dp[2][1010][33]; 32 33 int main() 34 { 35 for (int i=1;i<=1000;i++){ 36 for (int j=1;j<=1000;j++) 37 lcm[i][j] = i*j/gcd(i,j); 38 lcm[0][i] = i; 39 } 40 while (scanf("%d%d%d",&N,&M,&K)==3) 41 { 42 init(); 43 // printf("%d\n",lcm[9][18]); 44 memset(dp,0,sizeof(dp)); 45 dp[0][0][1] = 1; 46 int t = 0,s; 47 for (int k=1;k<=K;k++) 48 { 49 s = t; 50 t = 1 - t; 51 for (int i=0;i<=N;i++) 52 for (int j=0;j<=tot;j++) 53 dp[t][i][j] = 0; 54 for (int i=0;i<=N;i++) 55 for (int j=1;j<=tot;j++) 56 if (dp[s][i][j] > 0) 57 { 58 //printf("%d %d\n",i,seq[j]); 59 for (int jj=1;jj<=tot;jj++){ 60 int sum = i + seq[jj]; 61 int lll = lcm[seq[j]][seq[jj]]; 62 if (sum<=N && lll<=M) 63 { 64 // printf("%d %d %d %d\n",sum,seq[j],seq[jj],lll); 65 int ppp = hash[lll]; 66 dp[t][sum][ppp] = (dp[t][sum][ppp] + dp[s][i][j]) % MOD; 67 } 68 } 69 70 } 71 //printf("********************\n"); 72 } 73 LL ans = (dp[t][N][tot] % MOD + MOD) % MOD; 74 75 printf("%I64d\n",ans); 76 } 77 return 0; 78 }