P5009 [yLOI2018] 不老梦 题解
这个小丑看了好久题目才发现保证
好像与其他题解做法稍有不同。
思路#
其他题解的标记做法非常复杂,怎么办。
我们可以使用适用性可加强大的矩阵乘法。
我们考虑维护:
分别表示
分操作考虑。
时间往后移#
也就是所有的
那么在矩阵上也就是乘上:
其中
区间加 #
在矩阵上为:
区间加 #
在矩阵上为:
区间加 #
在矩阵上为:
应当都是比较容易理解的。
从这里就可以看出矩阵乘法的好处了,更加容易思考与实现。
然后直接使用线段树维护即可。
时间复杂度:
Code#
有一些细节。
如果直接这么写的话会只有
会有一些点
合理减少取模后。
可以得到
将矩阵循环展开,减少一直为
就可以过了。
当然,如果你经常写数据结构维护矩阵,这些都是基本的(都是因为一般朴素的会被卡。
代码比较冗长,但很好写(最长的是复制粘贴的循环展开)。
#include <bits/stdc++.h>
using namespace std;
#define x first
#define y second
#define mp(x, y) make_pair(x, y)
#define fro(i, x, y) for(int i = (x);i <= (y);i++)
#define pre(i, x, y) for(int i = (x);i >= (y);i--)
#define dbg cerr << "Line " << __LINE__ << ": "
#define EVAL(x) #x " = " << (x)
typedef int64_t i64;
typedef uint32_t u32;
typedef uint64_t u64;
typedef __int128_t i128;
typedef __uint128_t u128;
typedef pair<int, int> PII;
bool ed;
const int N = 200010;
const int mod = 1e8 + 7;
int n, m, vis[N<<1];
inline void add(i64 &x, int y)
{ x = (x + y) + (x + y >= mod ? -mod : 0); }
struct Mat
{
i64 a[5][5]{};
inline void init() { a[0][0] = a[1][1] = a[2][2] = a[3][3] = a[4][4] = 1; }
inline void init(i64 v_, i64 ab_, i64 a_, i64 b_)
{ a[0][0] = v_, a[0][1] = ab_, a[0][2] = a_, a[0][3] = b_, a[0][4] = 1; }
inline void clear() { memset(a, 0, sizeof a); }
inline Mat operator*(const Mat &tmp) const
{
Mat c;
c.a[0][0] = (a[0][0] * tmp.a[0][0] + a[0][1] * tmp.a[1][0] + a[0][2] * tmp.a[2][0] + a[0][3] * tmp.a[3][0] + a[0][4] * tmp.a[4][0]) % mod;
c.a[0][1] = (a[0][0] * tmp.a[0][1] + a[0][1] * tmp.a[1][1] + a[0][2] * tmp.a[2][1] + a[0][3] * tmp.a[3][1] + a[0][4] * tmp.a[4][1]) % mod;
c.a[0][2] = (a[0][0] * tmp.a[0][2] + a[0][1] * tmp.a[1][2] + a[0][2] * tmp.a[2][2] + a[0][3] * tmp.a[3][2] + a[0][4] * tmp.a[4][2]) % mod;
c.a[0][3] = (a[0][0] * tmp.a[0][3] + a[0][1] * tmp.a[1][3] + a[0][2] * tmp.a[2][3] + a[0][3] * tmp.a[3][3] + a[0][4] * tmp.a[4][3]) % mod;
c.a[0][4] = (a[0][0] * tmp.a[0][4] + a[0][1] * tmp.a[1][4] + a[0][2] * tmp.a[2][4] + a[0][3] * tmp.a[3][4] + a[0][4] * tmp.a[4][4]) % mod;
c.a[1][0] = (a[1][0] * tmp.a[0][0] + a[1][1] * tmp.a[1][0] + a[1][2] * tmp.a[2][0] + a[1][3] * tmp.a[3][0] + a[1][4] * tmp.a[4][0]) % mod;
c.a[1][1] = (a[1][0] * tmp.a[0][1] + a[1][1] * tmp.a[1][1] + a[1][2] * tmp.a[2][1] + a[1][3] * tmp.a[3][1] + a[1][4] * tmp.a[4][1]) % mod;
c.a[2][0] = (a[2][0] * tmp.a[0][0] + a[2][1] * tmp.a[1][0] + a[2][2] * tmp.a[2][0] + a[2][3] * tmp.a[3][0] + a[2][4] * tmp.a[4][0]) % mod;
c.a[2][1] = (a[2][0] * tmp.a[0][1] + a[2][1] * tmp.a[1][1] + a[2][2] * tmp.a[2][1] + a[2][3] * tmp.a[3][1] + a[2][4] * tmp.a[4][1]) % mod;
c.a[2][2] = (a[2][0] * tmp.a[0][2] + a[2][1] * tmp.a[1][2] + a[2][2] * tmp.a[2][2] + a[2][3] * tmp.a[3][2] + a[2][4] * tmp.a[4][2]) % mod;
c.a[3][0] = (a[3][0] * tmp.a[0][0] + a[3][1] * tmp.a[1][0] + a[3][2] * tmp.a[2][0] + a[3][3] * tmp.a[3][0] + a[3][4] * tmp.a[4][0]) % mod;
c.a[3][1] = (a[3][0] * tmp.a[0][1] + a[3][1] * tmp.a[1][1] + a[3][2] * tmp.a[2][1] + a[3][3] * tmp.a[3][1] + a[3][4] * tmp.a[4][1]) % mod;
c.a[3][3] = (a[3][0] * tmp.a[0][3] + a[3][1] * tmp.a[1][3] + a[3][2] * tmp.a[2][3] + a[3][3] * tmp.a[3][3] + a[3][4] * tmp.a[4][3]) % mod;
c.a[4][0] = (a[4][0] * tmp.a[0][0] + a[4][1] * tmp.a[1][0] + a[4][2] * tmp.a[2][0] + a[4][3] * tmp.a[3][0] + a[4][4] * tmp.a[4][0]) % mod;
c.a[4][1] = (a[4][0] * tmp.a[0][1] + a[4][1] * tmp.a[1][1] + a[4][2] * tmp.a[2][1] + a[4][3] * tmp.a[3][1] + a[4][4] * tmp.a[4][1]) % mod;
c.a[4][2] = (a[4][0] * tmp.a[0][2] + a[4][1] * tmp.a[1][2] + a[4][2] * tmp.a[2][2] + a[4][3] * tmp.a[3][2] + a[4][4] * tmp.a[4][2]) % mod;
c.a[4][3] = (a[4][0] * tmp.a[0][3] + a[4][1] * tmp.a[1][3] + a[4][2] * tmp.a[2][3] + a[4][3] * tmp.a[3][3] + a[4][4] * tmp.a[4][3]) % mod;
c.a[4][4] = (a[4][0] * tmp.a[0][4] + a[4][1] * tmp.a[1][4] + a[4][2] * tmp.a[2][4] + a[4][3] * tmp.a[3][4] + a[4][4] * tmp.a[4][4]) % mod;
return c;
}
inline Mat operator+(const Mat &tmp) const
{ Mat c; fro(i, 0, 4) c.a[0][i] = (a[0][i] + tmp.a[0][i]) - (a[0][i] + tmp.a[0][i] >= mod ? mod : 0); return c; }
} t[N<<1], tg[N<<1], mat[5];
#define ls (mid<<1)
#define rs (mid<<1|1)
inline void mo(i64 &x)
{ x = (x % mod + mod) % mod; }
inline void mat1(int t) { mat[1].a[1][0] = t; }
inline void mat2(int t) { mat[2].a[3][1] = mat[2].a[4][2] = t; }
inline void mat3(int t) { mat[3].a[2][1] = mat[3].a[4][3] = t; }
inline void mat4(int t) { mat[4].a[4][0] = t; }
inline void push(int p, const Mat &k)
{ t[p] = t[p] * k, tg[p] = tg[p] * k, vis[p] = 1; }
inline void pdo(int p, int mid)
{
if(vis[p])
{
push(ls, tg[p]), push(rs, tg[p]);
tg[p].clear(), tg[p].init(), vis[p] = 0;
}
}
inline void update(int p, int l, int r, int L, int R, int op)
{
if(L <= l && r <= R) return push(p, mat[op]);
int mid = (l + r) >> 1; pdo(p, mid);
if(mid >= L) update(ls, l, mid, L, R, op);
if(mid < R) update(rs, mid + 1, r, L, R, op);
t[p] = t[ls] + t[rs];
}
inline int ask(int p, int l, int r, int L, int R)
{
if(L <= l && r <= R) return t[p].a[0][0];
int mid = (l + r) >> 1; pdo(p, mid); i64 sum{};
if(mid >= L) add(sum, ask(ls, l, mid, L, R));
if(mid < R) add(sum, ask(rs, mid + 1, r, L, R));
return sum;
}
inline void build(int p, int l, int r)
{
tg[p].init();
if(l == r)
{
i64 v, a, b;
cin >> v >> a >> b;
mo(v), mo(a), mo(b);
t[p].init(v, a * b % mod, a, b);
return;
}
int mid = (l + r) >> 1;
build(ls, l, mid);
build(rs, mid + 1, r);
t[p] = t[ls] + t[rs];
}
inline void solve()
{
cin >> n >> m;
build(1, 1, n); i64 last = 0;
mat[1].init(), mat[2].init();
mat[3].init(), mat[4].init();
fro(i, 1, m)
{
i64 op, t_, x, y, z;
cin >> op >> t_ >> x >> y;
if(t_ != last) mat1(t_ - last), push(1, mat[1]), last = t_;
if(op != 1) cin >> z, mo(z);
if(op == 1) cout << ask(1, 1, n, x, y) << "\n";
if(op == 2) mat2(z), update(1, 1, n, x, y, 2);
if(op == 3) mat3(z), update(1, 1, n, x, y, 3);
if(op == 4) mat4(z), update(1, 1, n, x, y, 4);
}
}
bool st;
signed main()
{
ios::sync_with_stdio(0), cin.tie(0);
double Mib = fabs((&ed-&st)/1048576.), Lim = 500;
cerr << " Memory: " << Mib << "\n", assert(Mib<=Lim);
solve();
return 0;
}
作者:JiaY19
出处:https://www.cnblogs.com/JiaY19/p/17835102.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)