ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

题解 BZOJ4221 JOI2012 kangaroo

2021-10-16 17:00:54  阅读:283  来源: 互联网

标签:JOI2012 袋鼠 匹配 int 题解 kangaroo 袋子 const dp


分析

题目链接

认真读题可知: 若一只袋鼠已被装进袋子, 它的袋子仍可以装一只袋鼠; 若一个袋子已装了袋鼠, 它所属的袋鼠仍可以被装进袋子

所以袋鼠与其袋子的效果互不相关

于是我们可以将袋鼠和袋子分开, 问题便成了求袋鼠和袋子两两匹配至不能再匹配方案数

求方案数? 自然想到dp

为方便, 将袋鼠, 袋子从大到小排序, 自然想到以 考虑到第\(i\)只袋鼠 为阶段

转移时, 新加入的第\(i+1\)只袋鼠有3种可能:

  1. 与左边的未匹配的袋子形成匹配
  2. 左边没有未匹配的袋子了, 一个人也要坚强地活下去
  3. 这只袋鼠已经被左边的袋子提前匹配了

为什么要考虑到第3种可能?

因为如果每个袋子只考虑与当前的第\([1,i]\)只袋鼠匹配或者不匹配, 方案必然有缺漏, 显然有些袋子可以与第\([i+1,n]\)只袋鼠匹配

所以我们设出状态: \(dp[i][j][k]\)表示考虑到第\(i\)只袋鼠,其左边有\(j\)个袋子与第\([1,i]\)只袋鼠匹配,有\(k\)个袋子与第\([i+1,n]\)只袋鼠匹配的方案数

注意:因为我们只考虑到第\(i\)只袋鼠,所以\(k\)个向后匹配的袋子并没有在当前阶段形成确切的方案,只是提前拿前面的\(k\)个袋子在后面占了\(k\)个位置,为转移做铺垫,其带来的实际贡献应在后面的阶段转移考虑第3种可能时被计算(即贡献计算后延)

设\(t[i]\)表示第\(i\)只袋鼠左边的袋子数,于是转移呼之欲出:

  1. \(dp[i+1][j+1][k]+=dp[i][j][k]*(t[i+1]-j-k)\)
  2. \(dp[i+1][j][t[i+1]-j]+=dp[i][j][k]\)
  3. \(dp[i+1][j+1][k-1]+=dp[i][j][k]*k\)

答案统计就不多说了

代码

#include <bits/stdc++.h>

#define uns unsigned
#define rei register int
#define ll long long
#define db double

using namespace std;

const int inf = 0x3f3f3f3f;
const ll INF = (ll)1e18 + 5;
const db eps = 1e-9;

template<typename T> bool read(T &x) {
    x = 0;
    char f = 0, c = getchar();
    if(c == EOF) return 0;
    while(!isdigit(c)) {
	f = (c == '-'), c = getchar();
	if(c == EOF) return 0;
    }
    if(f) while(isdigit(c)) x = x * 10 - c + 48, c = getchar();
    else while(isdigit(c)) x = x * 10 + c - 48, c = getchar();
    return 1;
}

template<typename T> inline void bemin(T &x, T y) { x = x < y? x : y; }
template<typename T> inline void bemax(T &x, T y) { x = x > y? x : y; }

const int N = 305;
const int mod = 1e9 + 7;

inline void add(int &x, int y) {
    x = (x + y >= mod? x + y - mod : x + y);
}

int n, ans;

int a[N], b[N], t[N], dp[N][N][N];

bool cmp(int x, int y) { return x > y; }

int main() {
    read(n);
    for(rei i = 1; i <= n; ++i) {
	read(a[i]), read(b[i]);
    }
    sort(a + 1, a + 1 + n, cmp);
    sort(b + 1, b + 1 + n, cmp);
    int temp = 0;
    for(rei i = 1; i <= n; ++i) {
	while(temp < n && b[temp + 1] > a[i]) ++temp;
	t[i] = temp;
    }
    dp[0][0][0] = 1;
    for(rei i = 0; i < n; ++i) {
	for(rei j = 0; j <= i; ++j) {
	    for(rei k = 0; j + k <= t[i]; ++k) {
		int now = dp[i][j][k];
		add(dp[i + 1][j][t[i + 1] - j], now);
		if(k) add(dp[i + 1][j + 1][k - 1], (ll)now * k % mod);
		add(dp[i + 1][j + 1][k], (ll)now * (t[i + 1] - j - k) % mod);
	    }
	}
    }
    for(rei i = 0; i <= n; ++i) add(ans, dp[n][i][0]);
    cout << ans << "\n";
    return 0;
}

标签:JOI2012,袋鼠,匹配,int,题解,kangaroo,袋子,const,dp
来源: https://www.cnblogs.com/mfuqwq/p/15414592.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有