SRM 585 DIV1 L2

记录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);
}

 

posted @ 2013-07-28 13:31  litstrong  阅读(172)  评论(0编辑  收藏  举报