【题解】51nod1327 棋盘游戏

  那天和机房的同学们一起想了很久,然而并没有做出来……今天看了题解,的确比较巧妙,不过细细想来其实规律还是比较明显,在这里记录一下~

  当天自己做的时候,主要想到的是两点 : 1.按列dp 2.对行进行排序。虽然没有做出来,但做法的确和这两点是重合的。我们考虑强制满足左端点,然后 dp 右端点的方法,记录状态 \(f[i][j][k]\) 为 dp 到第 \(i\) 列时,有 \(j\) 列是空的,且还有 \(k\) 个右端点没有满足(这 \(k\) 个右端点的位置均 \(<= i\))。

  首先从 \(i\) 转移到 \(i + 1\) 的条件就是 \(j + 1 >= b[i + 1]\) 其中 b 数组存的是以 \(x\) 为左端点的行数。这样做的本质就是将行按照左端点从小到大排序之后依次满足,端点为 \(x\) 的就强制在转移到第 \(x\) 列的时候去进行考虑(一方面一定要满足,另一方面可以放的范围已经限制了)。转移的时候我们分成三种情况:强制第 \(i\) 列不放 / 放一个满足左端点,满足一个右端点和放在一个空白的位置。对于后面两种转移,只有当 \(j >= b[i + 1]\) 时才会发生(说明我们可以选择将多出来的这一行去用于满足右端点 、放在空白)。这样就只需要讨论一下满足的是哪一个右端点和空白,对于一起转移的满足的左端点乘上排列数以统计不同的方案就可以了。

  很棒的题,奈何自己太弱啦……加油ヾ(?°∇°?)??

#include <bits/stdc++.h>
using namespace std;
#define mod 1000000007
#define maxn 205
#define int long long
int n, m, a[maxn], b[maxn], c[maxn];
int ans, f[maxn][maxn][maxn];
int fac[maxn], P[maxn][maxn];

int read()
{
    int x = 0, k = 1;
    char c; c = getchar();
    while(c < ‘0‘ || c > ‘9‘) { if(c == ‘-‘) k = -1; c = getchar(); }
    while(c >= ‘0‘ && c <= ‘9‘) x = x * 10 + c - ‘0‘, c = getchar();
    return x * k;
}

void pre()
{
    for(int i = 0; i <= m; i ++) P[i][0] = 1;
    for(int i = 1; i <= m; i ++)
        for(int j = 1; j <= i; j ++)
            P[i][j] = (P[i - 1][j - 1] + P[i - 1][j]) % mod;
    fac[0] = 1;
    for(int i = 1; i <= m; i ++) fac[i] = fac[i - 1] * i % mod;
    for(int i = 1; i <= m; i ++)
        for(int j = 1; j <= i; j ++)
            P[i][j] = P[i][j] * fac[j] % mod;
}

void Up(int &x, int y) { x = (x + y) % mod; }

void DP()
{
    f[0][0][0] = 1;
    for(int i = 0; i < m; i ++)
        for(int j = 0; j <= i; j ++)
            for(int k = 0; k <= n; k ++)
            {
                if(!f[i][j][k]) continue;
                if(j + 1 >= b[i + 1])
                {
                    int tem = f[i][j][k] * P[j + 1][b[i + 1]] % mod;
                    Up(f[i + 1][j + 1 - b[i + 1]][k + c[i + 1]], tem);
                }
                if(j >= b[i + 1])
                {
                    int tem = f[i][j][k] * a[i + 1] % mod * P[j][b[i + 1]] % mod;
                    Up(f[i + 1][j - b[i + 1]][k + c[i + 1]], tem);
                    if(k + c[i + 1])
                    {
                        tem = f[i][j][k] * (k + c[i + 1]) % mod * P[j][b[i + 1]] % mod;
                        Up(f[i + 1][j - b[i + 1]][k + c[i + 1] - 1], tem);
                    }
                }
            }
}

signed main()
{
    n = read(), m = read();
    for(int i = 1; i <= n; i ++)
    {
        int l = read(), r = read();
        for(int j = l + 1; j <= m - r; j ++) a[j] ++;
        b[l] ++, c[m - r + 1] ++;
    }
    pre(); DP();
    for(int i = 0; i <= m; i ++) Up(ans, f[m][i][0]);
    printf("%lld\n", ans);
    return 0;
}

原文地址:https://www.cnblogs.com/twilight-sx/p/9571701.html

时间: 2024-10-09 09:22:50

【题解】51nod1327 棋盘游戏的相关文章

51nod1327 棋盘游戏

远古大坑 神仙DP状态设计题 https://blog.csdn.net/white_elephant/article/details/83592103 从行的角度入手,无论如何都要状压 每列最多放一个,所以从列的角度入手 每列会左端点结束,右端点出现,以及空位 个数设为:l[i],r[i],md[i] 直接决定当前列填在哪一行很困难,若直接记录还有多少行左半边没有填,那么并不知道哪些行的左半边之后会消失,无法转移 所以在这个左半边消失的时刻进行安排位置! 只要考虑之前预留了多少列即可,这些列都

棋盘游戏(二分图匹配)

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1281 棋盘游戏 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 3200    Accepted Submission(s): 1897 Problem Description 小 希和Gardon在玩一个游戏:对一个N*M的棋盘,在格子里放

1358 棋盘游戏[状压dp]

1358 棋盘游戏 时间限制: 1 s 空间限制: 64000 KB 题目等级 : 大师 Master 题解 查看运行结果 题目描述 Description 这个游戏在一个有10*10个格子的棋盘上进行,初始时棋子位于左上角,终点为右下角,棋盘上每个格子内有一个0到9的数字,每次棋子可以往右方或下方的相邻格子移动,求一条经过数字之和最小且经过0到9的所有数字的合法路径,输出其长度.(经过的数字包括左上角和右下角) 输入描述 Input Description 输入包含10行,每行10个数字,以空

hdu 1281 棋盘游戏(二分图匹配)

棋盘游戏 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 2786    Accepted Submission(s): 1630 Problem Description 小希和Gardon在玩一个游戏:对一个N*M的棋盘,在格子里放尽量多的一些国际象棋里面的"车",并且使得他们不能互相攻击,这当然很简单,但是Gardon限制

HDU1281: 棋盘游戏(二分图匹配)

棋盘游戏 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 6897    Accepted Submission(s): 4005 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1281 Description: 小希和Gardon在玩一个游戏:对一个N*M的棋盘,在格子里放尽量多的一些国际

洛谷 P1079 Vigen&#232;re 密码 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=1079 题目描述 16 世纪法国外交家 Blaise de Vigenère 设计了一种多表密码加密算法――Vigenère 密 码.Vigenère 密码的加密解密算法简单易用,且破译难度比较高,曾在美国南北战争中为 南军所广泛使用. 在密码学中,我们称需要加密的信息为明文,用 M 表示:称加密后的信息为密文,用 C 表示:而密钥是一种

8.8联考题解

今天的T1让我怀疑我是不是在做奥赛题--这考的是什么知识点啊这个,会不会用绝对值函数? Evensgn 的债务 时间限制: 1 Sec  内存限制: 128 MB 题目描述 Evensgn 有一群好朋友,他们经常互相借钱.假如说有三个好朋友A,B,C.A 欠 B 20 元,B 欠 C 20 元,总债务规模为 20+20=40 元.Evensgn 是个追求简约的人,他觉得这样的债务太繁杂了.他认为,上面的债务可以完全等价为 A 欠C20 元,B 既不欠别人,别人也不欠他.这样总债务规模就压缩到了 

POJ 2533 - Longest Ordered Subsequence(最长上升子序列) 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:http://poj.org/problem?id=2533 Description A numeric sequence of ai is ordered if a1 < a2 < ... < aN. Let the subsequence of the given numeric sequence (a1, a2, ..., aN) be any sequence (ai1, ai2, ..., aiK)

(leetcode题解)Pascal&#39;s Triangle

Pascal's Triangle  Given numRows, generate the first numRows of Pascal's triangle. For example, given numRows = 5,Return [ [1], [1,1], [1,2,1], [1,3,3,1], [1,4,6,4,1] ] 题意实现一个杨辉三角. 这道题只要注意了边界条件应该很好实现出来,C++实现如下 vector<vector<int>> generate(int