标签: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