题目
给出两个正整数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的分解方案总个数。
则可以有递推公式:
int tt = k*t%M;
dp[i + k][k][tt] += dp[i][j][t];
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-10-07 00:06:12