一个长了一张数学脸的dp!!dp[ i ][ s ][ t ] 表示第 i 个数,sum为 s ,lcm下标为 t 时的个数。显然,一个数的因子的lcm还是这个数的因子,所以我们的第三维用因子下标代替lcm,可以有效的减少枚举量。
#include<algorithm> #include<iostream> #include<cstring> #include<vector> #include<cstdio> #include<cmath> #include<set> #define LL long long #define CLR(a, b) memset(a, b, sizeof(a)) using namespace std; const int N = 1010; const int MOD = 1e9 + 7; int k, num, m; int dp[2][N][40]; int ok[N], f[N][N]; int gcd(int a, int b) { return b ? gcd(b, a % b) : a; } int lcm(int a, int b) { return a / gcd(a, b) * b; } int main() { //freopen("input.txt", "r", stdin); int n, i, j, s, t, tmd = 0; while(scanf("%d%d%d", &n, &m, &k) != EOF) { CLR(dp, 0);num = 0; for(i = 1; i <= m; i ++) { if(m % i == 0) ok[num ++] = i; }//num不超过32 for(i = 0; i < num; i ++) { for(j = 0; j < num; j ++) { t = lcm(ok[i], ok[j]); for(s = 0; s < num; s ++) { if(ok[s] == t) { f[i][j] = s; break; } } } } for(j = 0; j < num; j ++) { dp[0][ok[j]][j] = 1; } for(i = 1; i < k; i ++) { for(s = 0; s <= n; s ++)//一定记得初始化 { for(t = 0; t < num; t ++) { dp[i & 1][s][t] = 0; } } for(j = 0; j < num; j ++) { for(s = i; s <= n - (k - i - 1) - ok[j]; s ++) { for(t = 0; t < num; t ++) { dp[i&1][s+ok[j]][f[t][j]]= (dp[i&1][s+ok[j]][f[t][j]]+dp[1-(i&1)][s][t]) % MOD; } } } } printf("%d ", dp[(k - 1) & 1][n][num - 1]); } return 0; }