题目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3662
LCM的状态一定是M的约数,每次加入的数也是M的约数;
可以压缩LCM的状态到M的约数个; 需要预处理LCM;
#include <iostream> #include <cstdio> #include <sstream> #include <cstring> #include <string> #include <cmath> #include <vector> #include <queue> #include <stack> #include <map> #include <set> #include <algorithm> #include <functional> using namespace std; #define MOD 1000000007 int N, M, K; int restore[1010], compress[1010]; int dp[2][1010][110]; int LCM[1010][1010]; int cnt; int gcd (int a, int b) { return b == 0 ? a : gcd(b, a % b); } int lcm (int a, int b) { return a / gcd(a, b) * b; } int main() { for (int i = 1; i <= 1000; i++) for (int j = 1; j <= 1000; j++) LCM[i][j] = lcm(i, j); while (scanf("%d%d%d", &N, &M, &K) == 3) { memset(compress, -1, sizeof(compress)); memset(restore, -1, sizeof(restore)); cnt = 0; for (int i = 1; i <= M; i++) if (M % i == 0) { restore[cnt] = i; compress[i] = cnt++; } memset(dp[0], -1, sizeof(dp[0])); dp[0][0][0] = 1; for (int i = 1; i <= K; i++) { memset(dp[i&1], -1, sizeof(dp[i&1])); for (int j = i-1; j <= N; j++) { for (int k = 0; k < cnt; k++) { if (dp[(i+1)&1][j][k] == -1) continue; for (int r = 0; r < cnt && j+restore[r] <= N; r++) { int jj = j + restore[r]; int kk = LCM[ restore[k] ][ restore[r] ]; if (kk <= M && compress[kk] != -1) { kk = compress[kk]; if (dp[i&1][jj][kk] == -1) dp[i&1][jj][kk] = 0; dp[i&1][jj][kk] += dp[(i+1)&1][j][k]; if (dp[i&1][jj][kk] >= MOD) dp[i&1][jj][kk] %= MOD; } } } } } printf("%dn", dp[K&1][N][compress[M]] == -1 ? 0 : dp[K&1][N][compress[M]]); } return 0; }