Petrozavodsk Summer 2017 JOI TST 2012 Selection | Kangaroo | 动态规划

G: Kangaroo

题目大意

n(1n300) n ( 1 ≤ n ≤ 300 ) 只袋鼠,每个袋鼠大小为 ai a i ,袋子大小为 bi b i 。袋鼠袋鼠至多装1只袋鼠,且满足被装袋鼠的大小小于袋子的大小。一个装袋鼠的合法方案指的是不存在一只袋鼠可以装进其他袋鼠的袋子里。问有多少种装袋鼠的方法。

题解

fi,j,k f i , j , k 表示对于前 i i 大的袋鼠,被分成 j j 组,有 k k 个袋鼠的袋子必须要装袋鼠(即存在袋鼠能装进袋子里,但目前还没有装)。那么答案显然是 jfn,j,0 ∑ j f n , j , 0 ,即k=0表示没有袋鼠能装。

那么有3种情况:

  • i+1 i + 1 只袋鼠新开一组放,那么 fi,j,kfi+1,j+1,alli+1,j f i , j , k → f i + 1 , j + 1 , a l l i + 1 , j
  • i+1 i + 1 只袋鼠放进 k k 个袋鼠的袋子里,那么有 k k 种选择, kfi,j,kfi+1,j,k1 k f i , j , k → f i + 1 , j , k − 1
  • i+1 i + 1 只袋鼠放进 k k 个袋鼠以外的袋子里,那么有 alli,jk a l l i , j − k 种方案, (alli+1,jk)fi,j,kfi+1,j,k ( a l l i + 1 , j − k ) f i , j , k → f i + 1 , j , k

cnti c n t i 表示有多少只袋鼠可以装 i i
alli,j a l l i , j 表示前 i1 i − 1 只袋鼠已经有j组有多少只袋鼠还可以装 i i (因为有些袋鼠已经装了其他的袋鼠),那么有 alli=cnti(i1j) a l l i = c n t i − ( i − 1 − j ) 。因为 cnti c n t i 表示能装 i i 的袋鼠有多少只,那么如果已经装了其他袋鼠了的袋鼠,一定能装 i i ,因此我们只要 cnti c n t i 减去已经装了其他袋鼠了的袋鼠就可以得到还有多少只袋鼠能装 i i

那么剩下的就很简单了。。

#include 
#include 
#include 
#include 
using namespace std;
#define FOR(i,j,k) for(i=j;i<=k;++i)
#define rep(i,j,k) for(i=j;i
typedef long long ll;
const ll MOD = 1e9 + 7;
const int N = 305;
int included[N];
ll dp[2][N][N];
pair<int, int> c[N];
int main()
{
    int i, j, k, n;
    scanf("%d", &n);

    FOR(i,1,n) scanf("%d%d", &c[i].first, &c[i].second);
    sort(c + 1, c + n + 1, greaterint, int>>());
    FOR(i,1,n) FOR(j,1,i)
        if (c[i].first < c[j].second)
            included[i]++;

    ll ans = 0;
    dp[0][0][0] = 1;
    FOR(i,1,n) 
    {
        int p = i & 1;
        memset(dp[p], 0, sizeof dp[p]);
        FOR(j,0,i)
        {
            int t = included[i] - (i - 1 - j);
            FOR(k,0,t)
            {
                (dp[p][j][k] += (dp[p ^ 1][j][k] * (t - k)) % MOD) %= MOD;
                if (k > 0) // 2.
                    (dp[p][j][k - 1] += (dp[p ^ 1][j][k] * k) % MOD) %= MOD;
                (dp[p][j + 1][t] += dp[p ^ 1][j][k]) %= MOD; // 1.
            }
        }
    }

    FOR(j,0,n)
        (ans += dp[n & 1][j][0]) %= MOD;
    printf("%lld\n", ans);

    return 0;
}

你可能感兴趣的:(区域赛,——动态规划——,Petrozavodsk)