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);

}

 

你可能感兴趣的:(div)