首页 > 其他分享 >洛谷 P9221 「TAOI-1」Pentiment 题解

洛谷 P9221 「TAOI-1」Pentiment 题解

时间:2023-07-25 17:13:02浏览次数:43  
标签:洛谷 题解 LL Pentiment 算法 vec sum se mod

Description

给定 \(n\times m\) 的矩阵,从第 \(1\) 行任意格子出发,每次向下、左、有走一步,有 \(q\) 个障碍不能经过,求走到第 \(n\) 行任意格子的方案。

对于所有数据,\(1\leq n,m\leq 10^9\),\(1\leq q\leq 10^5\)。

link:https://www.luogu.com.cn/problem/P9221

Solution

算法一

考虑朴素 DP,设 \(f_{i,j}\) 是从第 \(1\) 行任意格子出发,走到 \((i,j)\) 的方案数。枚举行 \(i\) 进行 DP,令 \(x,y\) 分别为 \((i,j)\) 左边和右边的第一个障碍,\(l=x+1,r=y-1\),则 \(\displaystyle f_{i,j}=\sum_{k=l}^{r}f_{i-1,k}\)。初值是对于所有 \(i\in[1,m]\),\(f_{0,i}=1\)。

时间复杂度 \(\mathcal{O}(nm+q)\),期望得分 \(25\)。

算法二

考虑优化算法一。对于每个 \([l,r]\),\(j\) 在这之间的 \(f_{i,j}\) 都相等,令这个值为 \(k\)。考虑珂朵莉树(颜色段均摊),将三元组 \((l,r,k)\) 放入容器进行操作。由于每次遍历上行的所有区间,所以放入 vector 即可。每次转移时使用双指针维护区间的和。

时间复杂度 \(\mathcal{O}(n+q)\),期望得分 \(45\)。

算法三

考虑 \(q=0\) 的部分分。\(q=0\) 即每行都是 \(l=1,r=m\)。观察转移方程可知答案为 \(m^{n+1}\)。

时间复杂度 \(\mathcal{O}(\log n)\),期望得分 \(10\)。

算法四

对有障碍的行跑算法二,没有障碍的行跑算法三即可。算法三有些改动,设当前行(有障碍)为 \(i\),上一行有障碍的是 \(p\) 且 \(p<i-1\),可以将上一行直接处理为 \(\displaystyle(1,m,m^{i-p-2}\times\sum_{j=1}^{m}f_{p,j})\)。需要特判没有做到第 \(n\) 行的情况。

时间复杂度 \(\mathcal{O}(q\log n)\),期望得分 \(100\)。

算法五

使用光速幂(分块预处理的快速幂),钦定 \(B=\sqrt{n}+1\),处理出所有 \(0\leq i\leq B\) 的 \(m^i\) 与 \(m^{iB}\),即可做到 \(\mathcal{O}(1)\) 查询 \(m\) 的幂。

时间复杂度 \(\mathcal{O}(q+\sqrt{n})\),期望得分 \(100\)。

Code

#include <bits/stdc++.h>
#define fi first
#define se second
using namespace std;
namespace Milkcat {
	typedef long long LL;
	typedef pair<LL, LL> pii;
	const int N = 1e6 + 5, mod = 998244353;
	struct node { LL v, l, r; LL val() { return v * (r - l + 1); } }; // val:求整段区间数的和
	LL n, m, q, qwq, cnt, ans, p1[N], p2[N]; pii a[N];
	vector<node> vec, now;
	LL qpow(LL k) { return p1[k % cnt] * p2[k / cnt] % mod; }
	LL add(LL& x, LL y) { return x = ((x + y) % mod + mod) % mod; }
	int main() {
		cin >> n >> m >> q, cnt = sqrt(n) + 1, p1[0] = p2[0] = 1;
		for (int i = 1; i <= cnt; i ++) p1[i] = p1[i - 1] * m % mod;
    	for (int i = 1; i <= cnt; i ++) p2[i] = p2[i - 1] * p1[cnt] % mod; // 光速幂
		for (int i = 1; i <= q; i ++) cin >> a[i].fi >> a[i].se;
		vec.push_back({1, 1, m}), qwq = 0; // 初值
		for (int i = 1; i <= q; ) {
			if (a[i].fi - qwq > 1) {
				LL sum = 0, k = a[i].fi - qwq;
				for (node v : vec) add(sum, v.val());
				vector<node>().swap(vec), vec.push_back({sum * qpow(k - 2) % mod, 1, m});
			} // 算法三
			qwq = a[i].fi, vector<node>().swap(now);
			LL l = 0, r = 0, pre = 1, sum = vec.front().val();
			while (a[i].fi == qwq) {
				if (pre < a[i].se) now.push_back({0, pre, a[i].se - 1});
				now.push_back({-1, a[i].se, a[i].se}), pre = a[i].se + 1, i ++;
			}
			if (pre <= m) now.push_back({0, pre, m});
			for (node &v : now) {
				if (v.v == -1) { v.v = 0; continue; }
				while (vec[l].r < v.l) add(sum, -vec[l ++].val());
				while (vec[r].r < v.r) add(sum, vec[++ r].val());
				v.v = ((sum - vec[l].v * (v.l - vec[l].l) - vec[r].v * (vec[r].r - v.r)) % mod + mod) % mod;
			} // 算法二
			vec.swap(now);
		}
		if (qwq < n) {
			LL sum = 0, k = n - qwq + 1;
			for (node v : vec) add(sum, v.val());
			vector<node>().swap(vec), vec.push_back({sum * qpow(k - 2) % mod, 1, m});
		} // 特判没有做完
		for (node v : vec) add(ans, v.val());
		cout << ans << '\n';
		return 0;
	}
}
int main() {
    int T = 1;
    while (T --) Milkcat::main();
    return 0;
}

标签:洛谷,题解,LL,Pentiment,算法,vec,sum,se,mod
From: https://www.cnblogs.com/Milkcatqwq/p/17580329.html

相关文章

  • 题解 LGP2300【合并神犇】
    Problem随机\(n\)个正整数组成序列。将序列分尽量多的段数,使得前一段的和不大于后一段的和。求能分成多少段。输出\(n-ans\)。\(n\leq10^5\),值域不重要。Solution状态设计为:\(f_i=1+\min_{sum_i-sum_j\geqg_j}f_j\)表示前\(i\)个数字划分的最多段数,\(g_j\)定义为\(f_......
  • 洛谷 P3291 [SCOI2016] 妖怪
    设每只怪物经过环境影响后的攻击力和防守力分别为\(x_i,y_i\),则有:\(y_i=dnf_i-\dfracba(x_i-atk_i)\)。设\(k=-\dfracba\),则有\(y_i=kx_i+dnf_i-k\cdotatk_i\)。设直线\(l_i:y_i=kx_i+dnf_i-k\cdotatk_i\),第\(i\)只怪物在\((a,b)\)的环境下......
  • 洛谷P3629 [APIO2010] 巡逻题解
    题目链接P3629[APIO2010]巡逻-洛谷|计算机科学教育新生态(luogu.com.cn)思路n个村庄,n-1条道路,原图为树1.若k=0(不修建道路)那么答案为(n-1)*2 每个道路会走两遍2.若k为1(修建一条道路)设修建的道路(r1)所在的环长度为L那么答案为(n-1)*2-L+2可以看到r1所在环的道路只走了......
  • 题解 P1150 【Peter的烟】
    postedon2020-11-1410:00:20|under题解|source2023编者注:本篇题解的方法过于暴力,但是尊重历史。请不要太在意。—-教你们用栈做这道题原题传送门看到这题,第一反应是用stack做。我们可以把Peter手上的烟看作一个栈,一根烟就是一个元素,抽了\(n\)支烟就从栈里pop几个,......
  • 题解 P1008 【三连击】
    postedon2020-11-1217:25:10|under题解|source2023编者注:请尊重历史。本题正解是暴力枚举先引用我们老师的一句话:(无恶意)不会吧不会吧,不会还有人不会写三连击吧!废话不多说,开始解题:理解题目和做题思路P1008三连击题目链接:https://www.luogu.com.cn/problem/......
  • 题解 CF1501A 【Alexey and Train】
    postedon2021-03-1321:57:02|under题解|source简单模拟题,考验选手的读题能力和使用谷歌翻译的能力。先定义一个\(now=0\),我们最后算出来的结果为\(now\)。对于每个站(不包括第\(n\)站),我们需要加上\(3\)个部分:额外时间,now+=ex[i];第\(i-1\)站到第\(i\)站的时......
  • 题解 CF1501B 【Napoleon Cake】
    postedon2021-03-1617:42:06|under题解|source题目可以转化一下:给一个长为\(n\)的数组\(a\),请求出一个长为\(n\)的数组\(b\)。要求若\(a_i\)不为\(0\),则\([b_{i-a_i+1},b_i]\)这个区间要为\(1\)。知道这个题目意思就好办了。题目说\(n\leq2\times10^5\),......
  • 题解 CF1497C2 【k-LCM (hard version)】
    postedon2021-03-2009:09:40|under题解|source2023编者注:有一些链接点不进去,分别是cf1497c1的cf页面和https://www.cnblogs.com/caijianhong/p/Solution-cf1497c1.html此题与CF1497C1有异曲同工之妙。我们知道,\(\operatorname{lcm}(1,x)=x\),不难想到,\(\operato......
  • 题解 CF1497C1 【k-LCM (easy version)】
    postedon2021-03-2008:26:53|under题解|source看数据范围,\(1\leqT\leq10^4\),\(1\leqn\leq10^9\),显然是构造题。我们分三类讨论:\(n\bmod2=1\):显然可以先提出一个\(1\),再把\(n-1\)分成两半,\(\operatorname{lcm}(1,\frac{n-1}{2},\frac{n-1}{2})=\frac{n-1}{2}\le......
  • 题解 P7679 【[COCI2008-2009#5] JABUKA】
    postedon2021-07-0717:38:14|under题解|source设题目中分给每个朋友的苹果数为\(x\),显然有\(x\vertr\landx\vertg\),也就是\(x\vert\gcd(r,g)\)。我们都知道,如果\(a\timesb=c\),那\(a\)和\(b\)都是\(c\)的因数,也就是说因数都是成对出现的(注意特判完全平方......