POJ 3181题目大意如下:
给出一个正整数N,并指定只能在1到K的范围内,使用这K中整数将N分解,问分解的方式有多少种。
如果按一般的方法来想,我们可以这样定义表达式:dp[i][j]表示使用前i种数来组成j的方法数,那么就有dp[i + 1][j] = Sigma(0, min{j, n(i + 1)})dp[i][j - k]。
但是这样算的话,就会是这样:
for (int i = 1; i < N; i++) { for (int j = 1; j <= K; j++) { for (int k = 0; k <= j; k += i + 1) dp[i + 1][j] += dp[i][j - k]; } }
dp[i][j] = dp[i][j - 1] + dp[i - j][j];
dp_H[i][j] = dp_H[i][j - 1] + dp_H[i - j][j] + (dp_L[i][j - 1] + dp_L[i - j][j]) / INF; dp_L[i][j] = (dp_L[i][j - 1] + dp_L[i - j][j]) % INF; (dp_H为高位,要考虑低位的进位,dp_L为低位,要考虑的是高位加法的低位部分)
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> using namespace std; const long long int INF = 1e18; long long int dp_L[1005], dp_H[1005]; int N, K; void solve() { memset(dp_L, 0, sizeof(dp_L)); memset(dp_H, 0, sizeof(dp_H)); dp_L[0] = 1; for (int j = 1; j <= K; j++) { for (int i = 1; i <= N; i++) { if (j <= i) { dp_H[i] = dp_H[i] + dp_H[i - j] + (dp_L[i] + dp_L[i - j]) / INF; dp_L[i] = (dp_L[i] + dp_L[i - j]) % INF; } } } if (dp_H[N])printf("%lld", dp_H[N]); printf("%lld\n", dp_L[N]); } int main(int argc, const char * argv[]) { // insert code here... scanf("%d %d", &N, &K); solve(); return 0; }