题面:求出满足以下条件的 n*m 的 01 矩阵个数:

    (1)第 i 行第 1~li 列恰好有 1 个 1 (li+1到ri-1不能放1)

    (2)第 i 行第 ri~m 列恰好有 1 个 1。

    (3)每列至多有 1 个 1

    对于 20%的数据,n,m<=12。

    对于 40%的数据,n,m<=50。

    对于 70%的数据,n,m<=300。

    对于 100%的数据,n,m<=3000,1<=li<ri<=m。

(考试前一天晚上玩过头了,整场考试直接划水,本题打了个状压,想不出来怎么优化就跳了)

 通过对题目的初步分析 本题是一类计数问题

  那么考虑这类问题解法通常为应用计数类DP或数学模型求解(本题显然DP色彩很浓厚)

然而 无论应用实际意义,数学模型都无法推出完整的式子 那么我们就需要思考DP类做法(事实上DP也是更为通用的做法)

  常规思考 问题状态有行,列,点 很容易想出状压DP的做法f[i][j]代表进行到第i行同时第i行状态为j

然而根据数据范围状压只能拿到20pts,显然不是正解 问题在于对于较大的m无法记录其状态 这样 直接否定了对行进行状压的过程

  思考问题在于枚举同一行点的状态的时间空间复杂度无法承受 那么为我们就要尽量降低这种复杂度

一种很显然的想法是既然我们不能记录同一行点的状态 那么缩小问题 记录单个点的状态的代价显然是能接受的

  那么思路逐渐清晰 我们需要考虑问题中行或列与节点的关系

一种常规DP设计手法是根据目标设计状态,阶段与决策 那么应用到本题上 目标是求n*m矩阵在一定条件下合法放置1的不同矩阵数

倒推分解问题 得 问题实际上是行或列放置1方案数的转移

  因此 设计状态f[i][j]表示已经进行到i列 其中有j列中的1放置在右区间,那么我们最终的目标就是f[m][n];

(这道题DP设计很新颖,思维量较高,然而其本质仍然是计数类DP的设计理念:通过精确划分使得状态各决策间满足加法原理 子状态间满足乘法原理(不重不漏))

显然本题状态划分是基于左右区间的互斥性 也就是说通过分别计算当前状态左右区间合法方案数来推出当前状态合法方案数

  很容易想到对于右区间 f[i][j] = f[i - 1][j] + f[i - 1] * (r[i] - (j - 1))  <1>  //其中r[i]代表右区间在i列及其以右的区间总数 l[i]同理

而有趣的是本题左右区间计算并不是完全独立的 相反 左区间的计算正是基于右区间已知的情况下进行的 (这为我们进行DP设计,具体到状态转移提供了新思路)

公式并不难推 f[i][j] = A(i - j - l[i - 1],l[i] - l[i - 1])  <2> ;最终根据乘法原理 状态f[i][j] = <1> * <2>;

 1 #include<bits/stdc++.h>
2 using namespace std;
3 #define I int
4 #define LL long long
5 #define C char
6 #define RE register
7 #define L inline
8 const I mod = 998244353;
9 const I MAXN = 3050;
10 I n,m,l[MAXN],r[MAXN],j[MAXN],y[MAXN],f[MAXN][MAXN];
11 L I read(); L LL qpow(I,I); L LL A(I,I); L I getmin(I,I);
12 signed main(){
13 n = read(); m = read();j[0] = 1;f[0][0] = 1;
14 for(RE I i(1);i <= n; ++ i) ++l[read()],++r[read()];
15 for(RE I i(1);i <= m; ++ i) l[i] += l[i - 1],r[i] += r[i - 1];
16 for(RE I i(1);i <= m; ++ i) j[i] = 1ll * j[i - 1] * i % mod;
17 y[m] = qpow(j[m],mod - 2);
18 for(RE I i(m); i ; -- i) y[i - 1] = 1ll * y[i] * i % mod;
19 for(RE I i(1);i <= m; ++ i){
20 f[i][0] = 1ll * f[i - 1][0] * A(i - l[i - 1],l[i] - l[i - 1]) % mod;
21 for(RE I j(1);j <= getmin(n,i); ++ j)
22 f[i][j] = (f[i - 1][j] + 1ll * f[i - 1][j - 1] * (r[i] - j + 1)%mod) * A(i - j - l[i - 1],l[i] - l[i - 1]) % mod;
23 }printf("%d\n",f[m][n]);
24 }
25 L I read(){ RE I x(0); RE C z = getchar(); while(!isdigit(z)) z = getchar(); while(isdigit(z)) x = (x << 3) + (x << 1) + (z ^ 48),z = getchar(); return x; }
26 L LL qpow(I a,I b){
27 LL res(1),base(a);
28 while(b){
29 if(b & 1) res = 1ll * res * base % mod;
30 base = 1ll * base * base % mod;
31 b >>= 1;
32 }return res; }
33 L LL A(I n,I m){ if(m > n) return 0; return 1ll * j[n] * y[n - m] % mod; }
34 L I getmin(I a,I b){ return a < b ? a : b; }

总的来说本题真的是DP中一道精彩的问题 对于DP状态设计,决策都提供了较为新颖的思路 建议反复咀嚼

NOIP模拟5 T2的更多相关文章

  1. noip模拟6(T2更新

    由于蒟弱目前还没调出T1和T2,所以先写T3和T4.(T1T2更完辣! update in 6.12 07:19 T3 大佬 题目描述: 他发现katarina大佬真是太强了,于是就学习了一下kata ...

  2. NOIP 模拟4 T2

    本题属于二和一问题 子问题相互对称 考虑对于问题一:知a求b 那么根据b数组定义式 显然能发现问题在于如何求dis(最短路) 有很多算法可供选择 dijsktra,floyed,bfs/dfs,spf ...

  3. 20161003 NOIP 模拟赛 T2 解题报告

    Weed duyege的电脑上面已经长草了,经过辨认上面有金坷垃的痕迹. 为了查出真相,duyege 准备修好电脑之后再进行一次金坷垃的模拟实验. 电脑上面有若干层金坷垃,每次只能在上面撒上一层高度为 ...

  4. 20161023 NOIP 模拟赛 T2 解题报告

    Task 2.回文串计数 (calc.pas/calc.c/calc.cpp) [题目描述] 虽然是一名理科生,Mcx常常声称自己是一名真正的文科生.不知为何,他对于背诵总有一种莫名的热爱,这也促使他 ...

  5. 20161005 NOIP 模拟赛 T2 解题报告

    beautiful 2.1 题目描述 一个长度为 n 的序列,对于每个位置 i 的数 ai 都有一个优美值,其定义是:找到序列中最 长的一段 [l, r],满足 l ≤ i ≤ r,且 [l, r] ...

  6. 神奇的NOIP模拟赛 T2 LGTB 学分块

    LGTB 学分块 LGTB 最近在学分块,但是他太菜了,分的块数量太多他就混乱了,所以只能分成3 块今天他得到了一个数组,他突然也想把它分块,他想知道,把这个数组分成3 块,块可以为空.假设3 块各自 ...

  7. 2018.02.12 noip模拟赛T2

    二兵的赌注 Description游戏中,二兵要进入了一家奇怪的赌场.赌场中有n个庄家,每个庄家都可以猜大猜小,猜一次一元钱.每一次开彩前,你都可以到任意个庄家那里下赌注.如果开彩结果是大,你就可以得 ...

  8. ztz11的noip模拟赛T2:查房

    链接: https://www.luogu.org/problemnew/show/U46611 思路: 这道题告你n-1条边就是骗你的 部分分也是骗你的 这道题连对边5分钟的事 一个点对另一个点有影 ...

  9. 2018.10.30 NOIp模拟赛T2 数字对

    [题目描述] 小 H 是个善于思考的学生,现在她又在思考一个有关序列的问题.        她的面前浮现出一个长度为 n 的序列{ai},她想找出一段区间[L, R](1 <= L <= ...

  10. NOIP模拟18 T2

    不知道为什么很多人拒绝这题打搜索...其实搜索在充分剪枝后时间是非常优秀的,不管数据怎样基本都可跑出 首先一个显然结论:对于某种状态,他抓到的小精灵一定是一个连续的区间. 因此我们可以枚举这个区间的左 ...

随机推荐

  1. Thinkphp之PHPExcel类库函数的官方读取的几个例子

    1.使用 PHPExcel_IOFactory 读取文件 $objPHPExcel = PHPExcel_IOFactory::load($inputFileName); 2.使用一个特定的读取类,读 ...

  2. 【日志追踪】(微服务应用和单体应用)-logback中的MDC机制

    一.MDC介绍 MDC(Mapped Diagnostic Contexts)映射诊断上下文,该特征是logback提供的一种方便在多线程条件下的记录日志的功能, 某些应用程序采用多线程的方式来处理多 ...

  3. Python简易远控(单线程版)

    1. 技术:管道通信,流文件处理,socket基础 2. Tips: 默认IP:127.0.0.1 默认端口:7676 3. 代码样例: 服务端: #!/usr/bin/env python # en ...

  4. Linux中环境变量的设置

    目录 环境变量 Shell定义的环境变量 查看环境变量 Linux下环境变量的设置 环境变量 在Windows 系统下,很多软件安装都需要配置环境变量,比如 安装 jdk ,如果不配置环境变量,在非软 ...

  5. Python中的Pexpect模块的简单使用

    Pexpect 是一个用来启动子程序并对其进行自动控制的 Python 模块. Pexpect 可以用来和像 ssh.ftp.passwd.telnet 等命令行程序进行自动交互.以下所有代码都是在K ...

  6. Python脚本暴力破解SSH口令以及构建僵尸网络(pxssh)

    目录 暴力破解SSH口令 SSH远端执行命令 构建僵尸网络 环境:Kali Linux  python 2.7.13 暴力破解SSH口令 Pxssh是pexpect库的ssh专用脚本,他能用预先写好的 ...

  7. POJ1376简单广搜

    题意:       给你一个n*m的矩阵,然后给你机器人的起点和终点,还有起点的方向,然后每次机器人有两种操作,左右旋转90度,或者是朝着原来的方向走1,2或者3步,机器人再走的过程中不能碰到格子,也 ...

  8. Node-Web模块

    创建服务端------------------------------------------------------ var http = require('http'); var fs = req ...

  9. HellowWorld详解

    1.随便新建一个文件夹,存放代码 2.在文件夹中新建一个Java文件 新建一个.txt文本文档-->将扩展名.txt修改为.java 注:如果创建的文本文档没有显示扩展名,则有如下方法: 方法一 ...

  10. JavaScript 包管理器 -Yarn

    Fast, reliable, and secure dependency management. 官网地址 Github 特性 离线模式:如果您之前下载了软件包,则可以在没有任何互联网连接的情况下安 ...