NOIP模拟5 T2
题面:求出满足以下条件的 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的更多相关文章
- noip模拟6(T2更新
由于蒟弱目前还没调出T1和T2,所以先写T3和T4.(T1T2更完辣! update in 6.12 07:19 T3 大佬 题目描述: 他发现katarina大佬真是太强了,于是就学习了一下kata ...
- NOIP 模拟4 T2
本题属于二和一问题 子问题相互对称 考虑对于问题一:知a求b 那么根据b数组定义式 显然能发现问题在于如何求dis(最短路) 有很多算法可供选择 dijsktra,floyed,bfs/dfs,spf ...
- 20161003 NOIP 模拟赛 T2 解题报告
Weed duyege的电脑上面已经长草了,经过辨认上面有金坷垃的痕迹. 为了查出真相,duyege 准备修好电脑之后再进行一次金坷垃的模拟实验. 电脑上面有若干层金坷垃,每次只能在上面撒上一层高度为 ...
- 20161023 NOIP 模拟赛 T2 解题报告
Task 2.回文串计数 (calc.pas/calc.c/calc.cpp) [题目描述] 虽然是一名理科生,Mcx常常声称自己是一名真正的文科生.不知为何,他对于背诵总有一种莫名的热爱,这也促使他 ...
- 20161005 NOIP 模拟赛 T2 解题报告
beautiful 2.1 题目描述 一个长度为 n 的序列,对于每个位置 i 的数 ai 都有一个优美值,其定义是:找到序列中最 长的一段 [l, r],满足 l ≤ i ≤ r,且 [l, r] ...
- 神奇的NOIP模拟赛 T2 LGTB 学分块
LGTB 学分块 LGTB 最近在学分块,但是他太菜了,分的块数量太多他就混乱了,所以只能分成3 块今天他得到了一个数组,他突然也想把它分块,他想知道,把这个数组分成3 块,块可以为空.假设3 块各自 ...
- 2018.02.12 noip模拟赛T2
二兵的赌注 Description游戏中,二兵要进入了一家奇怪的赌场.赌场中有n个庄家,每个庄家都可以猜大猜小,猜一次一元钱.每一次开彩前,你都可以到任意个庄家那里下赌注.如果开彩结果是大,你就可以得 ...
- ztz11的noip模拟赛T2:查房
链接: https://www.luogu.org/problemnew/show/U46611 思路: 这道题告你n-1条边就是骗你的 部分分也是骗你的 这道题连对边5分钟的事 一个点对另一个点有影 ...
- 2018.10.30 NOIp模拟赛T2 数字对
[题目描述] 小 H 是个善于思考的学生,现在她又在思考一个有关序列的问题. 她的面前浮现出一个长度为 n 的序列{ai},她想找出一段区间[L, R](1 <= L <= ...
- NOIP模拟18 T2
不知道为什么很多人拒绝这题打搜索...其实搜索在充分剪枝后时间是非常优秀的,不管数据怎样基本都可跑出 首先一个显然结论:对于某种状态,他抓到的小精灵一定是一个连续的区间. 因此我们可以枚举这个区间的左 ...
随机推荐
- OO Unit3 总结
OO Unit3 总结 OO课Unit3人际关系网JML应用技术回顾 BUAA.1823.邓新宇 2020/5/23 梳理JML语言的理论基础.应用工具链情况 方法规格 JML中,同一个方法在不同的条 ...
- 初中级php程序员面试时常见问题整理
初中级php程序员面试问题收集 感悟 有时候草率给出一个答案,比思而无果更糟糕 php基础 php的数据类型 php数据类型的转换 php魔术方法 php 的trait的概念及特点 php 虚拟类和接 ...
- Docker学习笔记---通俗易懂
目录 Docker 简介 Docker安装 Docker的基本组成 安装Docker 配置阿里云镜像加速 回顾helloworld流程 工作原理 Docker的常用命令 帮助命令 镜像命令 容器命令 ...
- 【运维--系统】nacos介绍和安装
目录: 简介 安装java 安装mysql 安装nacos 附录 简介 Nacos 致力于帮助您发现.配置和管理微服务.Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现.服务配置.服 ...
- Docker用Commit给容器做快照
关于 commit 镜像是容器的基础,每次执行 docker run 的时候都会指定哪个镜像作为容器运行的基础. 镜像是多层存储,每一层是在前一层的基础上进行修改:而容器同样也是多层存储,是在以镜像为 ...
- Portswigger web security academy:OS command injection
Portswigger web security academy:OS command injection 目录 Portswigger web security academy:OS command ...
- (数据科学学习手札120)Python+Dash快速web应用开发——整合数据库
本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 这是我的系列教程Python+Dash快速web ...
- 使用FileStream读写数据
这节讲一下使用FileStream读写数据,这是一个比较基础的流. FileStream类只能处理原始字节,所以它可以处理任何类型的文件. 先看一下它的构造方法: FileStream fs = ne ...
- Smss.exe加载win32k.sys过程总结
windows操作系统初始化 windows操作系统再初始化的过程中,当内核完全初始化而且各个组件也已经准备好后会加载一个个用户进程smss.exe(会话管理器),此进程会接着调用NtSetSyste ...
- Let's go!
第一次开通博客 心情还是很激动的,而且做出了这么好看的页面虽然都是用的别人的组件,自己不是很知道原理但是也很开心,以后会将自己学习的东西写成笔记发在上面