标签:des style blog http io ar color os sp
题目大意:给你三个数n,m,k。表示有k个数,他们的和为n,k个数的最小公倍数是m。让你求出符合这个条件的k个数的序列有多少种。
一看以为是个数论题,还尝试这各种分解m,然后进行组合数求情况。但是组合出来的数没法做减法啊。。。
结果是道dp题目。i,j,k表示到了第i个数此时和为j,最小公倍数为k。已经有了多少种组合方法了,直接向后推就可以了啊。数组太大开不开啊,滚动一下就可以了啊。
4 2 2 3 2 2
1 2HintThe first test case: the only solution is (2, 2). The second test case: the solution are (1, 2) and (2, 1).
#include <algorithm> #include <iostream> #include <stdlib.h> #include <string.h> #include <iomanip> #include <stdio.h> #include <string> #include <queue> #include <cmath> #include <time.h> #include <stack> #include <map> #include <set> #define eps 1e-8 #define M 1000100 ///#define LL long long #define LL __int64 #define INF 0x3f3f3f #define PI 3.1415926535898 #define mod 1000000007 using namespace std; const int maxn = 1010; int dp[2][maxn][maxn]; int lcm[maxn][maxn]; int num[maxn]; int LCM(int x, int y) { return (x*y)/(__gcd(x, y)); } void init() { for(int i = 1; i <= 1000; i++) for(int j = 1; j <= 1000; j++) lcm[i][j] = LCM(i, j); } int main() { int n, m, k; init(); while(~scanf("%d %d %d", &n, &m, &k)) { int ans = 0; for(int i = 1; i <= m; i++) if(!(m%i)) num[ans++] = i; for(int i = 0; i <= n; i++) for(int j = 0; j < ans; j++) dp[0][i][num[j]] = 0; dp[0][0][1] = 1; int now = 0; for(int i = 1; i <= k; i++) { now ^= 1; for(int si = 0; si <= n; si++) for(int sj = 0; sj < ans; sj++) dp[now][si][num[sj]] = 0; for(int si = i-1; si <= n; si++) { for(int sj = 0; sj < ans; sj++) { if(!dp[now^1][si][num[sj]]) continue; for(int sx = 0; sx < ans; sx++) { int x = si+num[sx]; int y = lcm[num[sj]][num[sx]]; if(x > n || m%y) continue; dp[now][x][y] += dp[now^1][si][num[sj]]; dp[now][x][y] %= mod; } } } } printf("%d\n",dp[now][n][m]%mod); } return 0; }
标签:des style blog http io ar color os sp
原文地址:http://blog.csdn.net/xu12110501127/article/details/41447361