hiho1096_divided_product

题目

给出两个正整数N和M, N <= 100, M <= 50, 可以将N分解成若干个不相等的正整数A1, A2... Ak的和,且A1, A2 ... Ak的乘积为M的倍数。即 
N = A1 + A2 + ... + Ak; 
A1*A2*...Ak % M = 0; 
求可以有多少种分解方式? 
题目链接: divided product

分析

直接DFS搜索,DFS(cur_sum, cur_max_num, cur_product) 枚举出总和为N的,且各个数字不断增加的方案,然后判断他们的乘积是否等于M的倍数。实现复杂度为:(2^t, t 为几十的量级),显然不行; 
考虑动态规划来解决: 
    维护状态 dp[i][j][t] 表示 A1,A2...Ak的总和为i,且最大的数字Ak等于j,A1*A2..A*k的结果模M为t的分解方案总个数。 
则可以有递推公式:

  1. int tt = k*t%M;
  2. dp[i + k][k][tt] += dp[i][j][t];
  3. dp[i + k][k][tt] %= mod;

其中需要注意 边界条件 dp[i][i][i%M] = 1.

实现

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<string>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<stack>
#include<unordered_map>
#include<unordered_set>
#include<algorithm>
using namespace std;
int dp[105][105][55];
int main(){
	const int mod = 1000000007;
	int n, m;
	scanf("%d %d", &n, &m);
	memset(dp, 0, sizeof(dp));
	for (int i = 0; i <= n; i++){
		for (int j = 0; j <= i; j++){
			for (int k = j + 1; (k + i) <= n; k++){
				for (int t = 0; t < m; t++){
					if (i == 0)
						dp[k][k][k%m] = 1;
					else{
						int tt = k*t%m;
						dp[i + k][k][tt] += dp[i][j][t];
						dp[i + k][k][tt] %= mod;
					}
				}
			}
		}
	}
	int result = 0;
	for (int i = 1; i <= n; i++)
		result = (result + dp[n][i][0]) % mod;
	printf("%d\n", result);
	return 0;
}
时间: 2024-08-05 03:05:57

hiho1096_divided_product的相关文章