@loj - 3157@「NOI2019」机器人
@description@
小 R 喜欢研究机器人。
最近,小 R 新研制出了两种机器人,分别是 P 型机器人和 Q 型机器人。现在他要测试这两种机器人的移动能力,测试在从左到右排成一排的 \(n\) 个柱子上进行,柱子用 \(1\sim n\) 依次编号,\(i\) 号柱子的高度为一个正整数 \(h_i\)。机器人只能在相邻柱子间移动,即:若机器人当前在 \(i\) 号柱子上,它只能尝试移动到 \(i - 1\) 号和 \(i + 1\) 号柱子上。
每次测试,小 R 会选取一个起点 \(s\),并将两种机器人均放置在 \(s\) 号柱子上。随后它们会按自己的规则移动。
P 型机器人会一直向左移动,但它无法移动到比起点 \(s\) 更高的柱子上。更具体地,P 型机器人在 \(l\ (l\leq s)\) 号柱子停止移动,当且仅当下列两个条件均成立:
- \(l = 1\) 或 \(h_{l-1}>h_s\);
- 对于满足 \(l\leq j \leq s\) 的 \(j\),有 \(h_j \leq h_s\)。
Q 型机器人会一直向右移动,但它只能移动到比起点 \(s\) 更低的柱子上。更具体地,Q 型机器人在 \(r\ (r\leq s)\) 号柱子停止移动,当且仅当下列两个条件均成立:
- \(r = n\) 或 \(h_{r+1} \geq h_s\);
- 对于满足 \(s < j \leq j\) 的 \(j\),有 \(h_j < h_s\)。
现在,小 R 可以设置每根柱子的高度,\(i\) 号柱子可选择的高度范围为 \([A_i, B_i]\),即 \(A_i\leq h_i \leq B_i\)。小 R 希望无论测试的起点 \(s\) 选在哪里,两种机器人移动过的柱子数量的差的绝对值都小于等于 \(2\)。他想知道有多少种柱子高度的设置方案满足要求,小 R 认为两种方案不同当且仅当存在一个 \(k\),使得两种方案中 \(k\) 号柱子的高度不同。请你告诉他满足要求的方案数模 \(10^9 + 7\) 后的结果。
@solution@
定义 \(dp(l, r, k)\) 表示区间 \([l, r]\) 的最大高度为 \(k\) 的方案数,枚举最大高度所在位置转移。
注意到合法的 \([l, r]\) 个数 \(m\) 不会很多,当 \(n \leq 300\) 时 \(m_{max} = 2220\),因此用前缀和优化后可以得到 50 分的好成绩。
不难猜测到 \(dp(l, r, k)\) 是一个关于 \(k\) 的分段多项式函数,且最高次数为 \(O(r-l+1)\)。
证明也很简单,观察发现转移只有两种操作:(几乎)对应位置相乘;求前缀和。
将 \([A_i, B_i+1)\) 离散化得到 \(O(n)\) 个高度区间,满足对于区间 \([L, R)\) 内的所有高度,每个柱子的合法性不改变。
也就是说这 \(O(n)\) 个区间即是分段函数的分界点。
如果我们把 \(dp(l, r, L-1)\) 看作关于区间 \([l, r]\) 的常量 \(c_{l, r}\),则每个 \(dp(l, r)\) 都可以表示成关于 \(k-L\) 的,最高次数 $\leq $ \(d = O(\min\{n, R-L+1)\})\) 的多项式函数。
对 \(x=0,1,\dots d\) 拉格朗日插值可以做到 \(O(n^2m)\),能获得 95 分的好成绩。
注意到最高次数可以继续缩到 \(d_{l, r} = O(\min\{r-l+1, R-L+1)\})\)。
即使父状态可能会用到,最多也只是 \(2(r-l+1)\)(因为转移是几乎等分区间)。需要的时候再插值插出来即可。
这样就能获得 100 分的好成绩。
这个优化我虽然不会分析时间复杂度不过感觉挺对的。
@accepted code@
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef pair<int, int> pii;
#define fi first
#define se second
#define pr make_pair
const int MOD = int(1E9) + 7;
const int MAXN = 310;
const int MAX = 2222;
inline int add(int x, int y) {x += y; return x >= MOD ? x - MOD : x;}
inline int sub(int x, int y) {x -= y; return x < 0 ? x + MOD : x;}
inline int mul(int x, int y) {return (int)(1LL * x * y % MOD);}
int pow_mod(int b, int p) {
	int ret = 1;
	for(int i=p;i;i>>=1,b=mul(b,b))
		if( i & 1 ) ret = mul(ret, b);
	return ret;
}
int fct[MAXN + 5], ifct[MAXN + 5];
void init() {
	fct[0] = ifct[0] = 1;
	for(int i=1;i<=MAXN;i++) {
		fct[i] = mul(fct[i - 1], i);
		ifct[i] = pow_mod(fct[i], MOD - 2);
	}
}
int lf[MAXN + 5], rf[MAXN + 5], a[MAXN + 5];
int get(int n, int x, int *y) {
	lf[0] = x; for(int i=1;i<=n;i++) lf[i] = mul(lf[i - 1], sub(x, i));
	rf[n] = sub(x, n); for(int i=n-1;i>=0;i--) rf[i] = mul(rf[i + 1], sub(x, i));
	int ans = 0;
	for(int i=0;i<=n;i++) {
		int del = ((n - i) & 1) ? sub(0, mul(ifct[i], ifct[n-i])) : mul(ifct[i], ifct[n-i]);
		if( i != 0 ) del = mul(del, lf[i - 1]);
		if( i != n ) del = mul(del, rf[i + 1]);
		ans = add(ans, mul(del, y[i]));
	}
	return ans;
}
int id[MAXN + 5][MAXN + 5], cnt;
void get_id(int l, int r) {
	if( id[l][r] != -1 ) return ;
	if( l > r ) {
		id[l][r] = 0;
		return ;
	}
	id[l][r] = (++cnt);
	for(int i=l;i<=r;i++)
		if( abs((i - l) - (r - i)) <= 2 )
			get_id(l, i - 1), get_id(i + 1, r);
}
int c[MAX + 5], dp[MAX + 5][MAXN + 5], dg[MAX + 5], mxd[MAX + 5], deg;
void update(int x, int newdg) {
	for(int i=dg[x]+1;i<=newdg;i++)
		dp[x][i] = get(dg[x], i, dp[x]);
	dg[x] = max(dg[x], newdg);
}
bool vis[MAX + 5], in[MAXN + 5];
int solve(int l, int r) {
	if( vis[id[l][r]] ) return id[l][r];
	int x = id[l][r]; mxd[x] = dg[x] = 0;
	for(int i=l;i<=r;i++) {
		if( abs((i - l) - (r - i)) <= 2 ) {
			int p = solve(l, i - 1), q = solve(i + 1, r);
			if( in[i] ) {
				int k = min(max(mxd[p] + mxd[q], dg[x]), deg - 1);
				update(p, k + 1), update(q, k), update(x, k);
				for(int j=0;j<=dg[x];j++)
					dp[x][j] = add(dp[x][j], mul(dp[p][j + 1], dp[q][j]));
				mxd[x] = k;
			}
		}
	}
	dg[x] = min(mxd[x], deg - 1);
	if( dg[x] == 0 && dp[x][0] == 0 )
		dp[x][0] = c[x];
	else {
		for(int i=dg[x];i>=0;i--) dp[x][i + 1] = dp[x][i];
		dp[x][0] = c[x], dg[x]++;
		for(int i=1;i<=dg[x];i++) dp[x][i] = add(dp[x][i], dp[x][i - 1]);
	}
	mxd[x] = dg[x];
	vis[id[l][r]] = true; return id[l][r];
}
int A[MAXN + 5], B[MAXN + 5], d[2*MAXN + 5], dcnt;
int main() {
	freopen("robot.in", "r", stdin);
	freopen("robot.out", "w", stdout);
	init(); int n; scanf("%d", &n);
	for(int i=1;i<=n;i++) {
		scanf("%d%d", &A[i], &B[i]), B[i]++;
		d[++dcnt] = A[i], d[++dcnt] = B[i];
	}
	sort(d + 1, d + dcnt + 1), dcnt = unique(d + 1, d + dcnt + 1) - d - 1;
	for(int i=1;i<=n;i++) {
		A[i] = lower_bound(d + 1, d + dcnt + 1, A[i]) - d;
		B[i] = lower_bound(d + 1, d + dcnt + 1, B[i]) - d;
	}
	memset(id, -1, sizeof id), get_id(1, n), c[0] = 1;
	for(int i=1;i<dcnt;i++) {
		for(int j=1;j<=n;j++)
			in[j] = (A[j] <= i && i < B[j]);
		deg = min(n, d[i + 1] - d[i]) + 3, solve(1, n);
		for(int j=0;j<=cnt;j++) {
			c[j] = get(mxd[j], d[i + 1] - d[i], dp[j]);
			for(int k=0;k<=dg[j];k++) dp[j][k] = 0;
			vis[j] = false;
		}
	}
	printf("%d\n", c[id[1][n]]);
}
@details@
该题还可以维护下降幂多项式系数做(方便求前缀和)。
对 \(x=0,1,\dots d\) 进行插值可以通过预处理阶乘逆元做到线性。
@loj - 3157@「NOI2019」机器人的更多相关文章
- LOJ 2550 「JSOI2018」机器人——找规律+DP
		题目:https://loj.ac/problem/2550 只会写20分的搜索…… #include<cstdio> #include<cstring> #include&l ... 
- LOJ 3158: 「NOI2019」序列
		题目传送门:LOJ #3158. 题意简述: 给定两个长度为 \(n\) 的正整数序列 \(a,b\),要求在每个序列中都选中 \(K\) 个下标,并且要保证同时在两个序列中都被选中的下标至少有 \( ... 
- LOJ 3160: 「NOI2019」斗主地
		题目传送门:LOJ #3160. 简要题意: 有一个长度为 \(n\) 的序列 \(a\),初始时 \(a_i=i\) 或 \(a_i=i^2\),这取决于 \(\mathrm{type}\) 的值. ... 
- LOJ 3159: 「NOI2019」弹跳
		题目传送门:LOJ #3159. 题意简述: 二维平面上有 \(n\) 个整点,给定每个整点的坐标 \((x_i,y_i)\). 有 \(m\) 种边,第 \(i\) 种边从 \(p_i\) 号点连向 ... 
- LOJ 3156: 「NOI2019」回家路线
		题目传送门:LOJ #3156. 题意简述: 有一张 \(n\) 个点 \(m\) 条边的有向图,边有两个权值 \(p_i\) 和 \(q_i\)(\(p_i<q_i\))表示若 \(p_i\) ... 
- loj3161「NOI2019」I 君的探险(随机化,整体二分)
		loj3161「NOI2019」I 君的探险(随机化,整体二分) loj Luogu 题解时间 对于 $ N \le 500 $ 的点,毫无疑问可以直接 $ O(n^2) $ 暴力询问解决. 考虑看起 ... 
- Loj #2192. 「SHOI2014」概率充电器
		Loj #2192. 「SHOI2014」概率充电器 题目描述 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品--概率充电器: 「采用全新纳米级加工技术,实现元件与导线能否通电完 ... 
- Loj #3096. 「SNOI2019」数论
		Loj #3096. 「SNOI2019」数论 题目描述 给出正整数 \(P, Q, T\),大小为 \(n\) 的整数集 \(A\) 和大小为 \(m\) 的整数集 \(B\),请你求出: \[ \ ... 
- Loj #3093. 「BJOI2019」光线
		Loj #3093. 「BJOI2019」光线 题目描述 当一束光打到一层玻璃上时,有一定比例的光会穿过这层玻璃,一定比例的光会被反射回去,剩下的光被玻璃吸收. 设对于任意 \(x\),有 \(x\t ... 
随机推荐
- FTP上传 -首先上传文件到的那台电脑得安装ftp
			/*↓↓↓↓ add upload ftp file 2014-03-16*/ /*↓↓↓↓ add 2014-03-16 ftp upload file*/ var $ftpse ... 
- 都说变量有七八种,到底谁是 Java 的亲儿子
			网上罗列了很多关于变量的理解,良莠不齐,不知道哪些是对的,哪些是错的,所以笔者就这些博客和自己的理解写出这篇文章,如果有不对的地方,希望读者能够指正,感谢. 变量是我们经常用到的一种,我在刚学 Jav ... 
- Spring 由构造函数自动装配
			Spring 由构造函数自动装配,这种模式与 byType 非常相似,但它应用于构造器参数. Spring 容器看作 beans,在 XML 配置文件中 beans 的 autowire 属性设置为 ... 
- 网鼎杯玄武组部分web题解
			查看JS,在JS中找到p14.php,直接copy下来console执行,输入战队的token就可以了 js_on 顺手输入一个 admin admin,看到下面的信息 欢迎admin这里是你的信息: ... 
- Istio DestinationRule 目标规则
			概念及示例 与VirtualService一样,DestinationRule也是 Istio 流量路由功能的关键部分.您可以将虚拟服务视为将流量如何路由到给定目标地址,然后使用目标规则来配置该目标的 ... 
- c# 优化代码的一些规则——使用is或as和强制类型转换的区别[三]
			前言 使用as和强制类型转换的时候的区别是否仅仅是代码形式上的区别. 答案是肯定不是的. 正文 看两段代码: object o = Factory.GetObject(); Student stude ... 
- [JavaWeb基础] 027.JAVA中使用Axis搭建webservice-示例实现(二)
			在上面的一个文章中,我们介绍了如何搭建Axis2的环境,也就是在MyEclipse中加入Axis的开发插件,那么,准备工作做好了之后,下面我们就用上一章的工具去搭建一个WebService的简单例子. ... 
- BJDCTF-WP
			BJDCTF 2nd WP 引言 由于在备考,所以没多少时间做,并且也实属是菜,所以就做了几个题目,这里就分享一下啦 Hi~ o( ̄▽ ̄)ブ [BJDCTF 2nd]fake google 知识点:S ... 
- 这个Maven依赖的问题,你敢说你没遇到过
			Maven 依赖没处理好的话经常会导致发生一些问题,非常烦.今天给大家分享一个依赖相关的问题,说不定你之前就遇到过. 问题背景 有个 ES 搜索的项目,刚开始还是好好的状态,过了一段时间,然后就发现启 ... 
- python调用大漠插件教程03窗口绑定实例
			怎样利用注册好的大漠对象来绑定窗口? 直接上代码,根据代码分析 from win32com.client import Dispatch import os from win32gui import ... 
