另一种解法

wawawa 发表于 2年前 · 关联问题 Making Colors

原来是矩阵快速幂,我已经忘光了....

设R, G, B各为一个三维向量,那么初始值为:

i=0, R(1, 0, 0), G(0, 1, 0), B(0, 0, 1) 那么对每个i,都进行一遍操作,得到R, G, B的三维向量

如例子:

i = 1, (1, 1 / 3, 2 / 3),(0, 2 / 3, 0), (0, 0, 1 / 3)

i= 2, (1/3, 1/9, 2/9), (2/3, 8/9, 5/9), (0, 0, 2/9)

那么对于每个询问l, r,我们只需要知道当i = l - 1时的三维向量和i=r时的三维向量,然后把当i=l-1的三维向量看成基底来表示当i = r时的三维向量,则可以得到l-r区间的操作和

即当i=l-1, R(a, b, c), G(d, e, f), B(g, h, i)

当i = r, R1(A, B, C), G1(D, E, F), B1(G, H, I)

设R1 = xR + yG + z * B 那么(x, y, z)为l-r区间的R的向量,其值就是x+y+z

对于求x, y, z可以用线性代数学到的自己推一下,G1,B1同理

然后就AC了...

#include <bits/stdc++.h> #define endl '\n' #define pb push_back using namespace std; using ll = long long; using db = double; using pii = pair<int , int>; const int mod = 1e9 + 7; const int maxn = 2e5 + 10; struct node { ll x, y, z; node operator * (const ll &d) { return {x * d % mod, y * d % mod, z * d % mod}; } node operator + (const node &p) { return {x + p.x % mod, y + p.y % mod, z + p.z % mod}; } node operator % (const ll &d) { return {x % mod, y % mod, z % mod}; } }R[maxn], G[maxn], B[maxn]; ll qpow(ll base, ll num) { ll ans = 1; while (num) { if (num & 1) ans = ans * base % mod; base = base * base % mod; num >>= 1; } return ans; } ll gg(ll a, ll b, ll c, ll d) { return (((a * b % mod) - (c * d % mod) + mod) % mod); } ll f(ll a, ll b, ll c, ll d, ll e, ll f, ll g, ll h, ll i, ll aa, ll bb, ll cc) { ll t = a * (e * i % mod - h * f % mod + mod) % mod; t = (t + b * (g * f % mod - d * i % mod + mod) % mod) % mod; t = (t + c * (d * h % mod - g * e % mod + mod) % mod) % mod; ll up = aa * gg(e, i, h, f) % mod + bb * gg(h, c, b, i) % mod + cc * gg(b, f, e, c); up %= mod; up = (up + aa * gg(g, f, d, i) % mod + bb * gg(a, i, g, c) + cc * gg(d, c, a, f) % mod) % mod; up = (up + aa * gg(d, h, g, e) % mod + bb * gg(g, b, a, h) + cc * gg(a, e, b, d) % mod) % mod; return up * qpow(t, mod - 2) % mod; } void solve() { ll n, m, i, j; cin >> n >> m; R[0] = {1, 0, 0}; G[0] = {0, 1, 0}; B[0] = {0, 0, 1}; ll t = qpow(3, mod - 2); for (i = 1; i <= n; i++) { cin >> j; if (j == 1) { R[i] = R[i - 1] + G[i - 1] * t % mod + B[i - 1] * 2 * t % mod; G[i] = G[i - 1] * 2 * t % mod; B[i] = B[i - 1] * t % mod; } else if (j == 2) { G[i] = G[i - 1] + B[i - 1] * t % mod + R[i - 1] * 2 * t % mod; R[i] = R[i - 1] * t % mod; B[i] = B[i - 1] * 2 * t % mod; } else { B[i] = B[i - 1] + R[i - 1] * t % mod + G[i - 1] * 2 * t % mod; G[i] = G[i - 1] * t % mod; R[i] = R[i - 1] * 2 * t % mod; } R[i] = R[i] % mod; G[i] = G[i] % mod; B[i] = B[i] % mod; } int l, r; while (m--) { cin >> l >> r; cout << f(R[l - 1].x, G[l - 1].x, B[l - 1].x, R[l - 1].y, G[l - 1].y, B[l - 1].y, R[l - 1].z, G[l - 1].z, B[l - 1].z, R[r].x, R[r].y, R[r].z) << ' '; cout << f(R[l - 1].x, G[l - 1].x, B[l - 1].x, R[l - 1].y, G[l - 1].y, B[l - 1].y, R[l - 1].z, G[l - 1].z, B[l - 1].z, G[r].x, G[r].y, G[r].z) << ' '; cout << f(R[l - 1].x, G[l - 1].x, B[l - 1].x, R[l - 1].y, G[l - 1].y, B[l - 1].y, R[l - 1].z, G[l - 1].z, B[l - 1].z, B[r].x, B[r].y, B[r].z) << '\n'; } } int main() { ios::sync_with_stdio(false); cin.tie(0), cout.tie(0); int T = 1; // cin >> T; while (T--) solve(); return 0; }

lr580 发表于 2年前

%%% //已超链接添加到题解页面(没想到还有 O(n+m) 的做法)

wawawa orz