记录dp(i, j)表示前i种卡片的排列,使得LISNumber为j的方法数。
#include <iostream> #include <vector> #include <string> #include <string.h> using namespace std; typedef long long int64; const int M = 1000000007; int64 dpC[1300][40]; int64 dpT[1300][40]; int64 sum[40]; int64 dp[40][1300]; class LISNumber { private: vector<int> num; public: int64 f(int i, int j); int count(vector <int> cardsnum, int K); }; int64 C(int m, int n) { if (m == 0 || n == 0 || m == n) { return 1; } if (dpC[m][n] != -1) { return dpC[m][n]; } return dpC[m][n] = (C(m - 1, n) + C(m - 1, n - 1)) % M; } // m plate, n ball int64 T(int m, int n) { // m >= 1 if (m == 1 || n == 0) { return 1; } if (dpT[m][n] != -1) { return dpT[m][n]; } return dpT[m][n] = (T(m - 1, n) + T(m, n - 1)) % M; } int64 LISNumber::f(int i , int j) { if (i == 0) { if (j == num[0]) { return dp[i][j] = 1; } else { return dp[i][j] = 0; } } if (j < num[i] || j > sum[i]) { return dp[i][j] = 0; } if (dp[i][j] != -1) { return dp[i][j]; } // num[i] <= j <= sum[i] dp[i][j] = 0; for (int k = 0; k <= num[i]; k++) { dp[i][j] += (((C(j - k, num[i] - k) * T(sum[i] + 1 - j, k)) % M) * f(i - 1, j - k)) % M; dp[i][j] %= M; } return dp[i][j]; } int LISNumber::count(vector <int> cardsnum, int K) { num = cardsnum; memset(dp, -1, sizeof(dp)); memset(dpC, -1, sizeof(dpC)); memset(dpT, -1, sizeof(dpT)); memset(sum, 0, sizeof(sum)); sum[0] = cardsnum[0]; for (int i = 1; i < cardsnum.size(); i++) { sum[i] = sum[i - 1] + cardsnum[i]; } return (int)f(cardsnum.size() - 1, K); }