我们显然可以变形为 (为了清楚,这里只是对式子进行了变形,没有把 交换)。但是我们需要注意有 U 和 R 的优先级的问题。比如下图:
原来的线经过了 ,是先 U 后 R,但是翻转之后,变成了先 R 后 U,所以我们需要将这条线向右平移 个单位,这样就是先 U 后 R,对应上了原来的字符串。
于是我们现在需要计算的就是 的答案。注意我们现在这个的定义域是 ,即我们需要计算最开始的 fu 贡献,但不计算最开始 fr 的贡献。所以可以得到 是属于 的。
回到上面那张图,我们发现 的部分的答案是不完整的,我们不能直接扔给下一个算,那么前面所经过的 个 fu 是需要提前乘入的,另外还有一个 fr。
然后我们考虑 这段区间如何计算。容易发现这就是我们需要递归的部分,但是注意,我们计算的定义域是 ,所以需要我们向左平移一个单位得到 ,所以应该递归到 f(c, c - b - 1, a, m - 1, fr, fu)()。
最后我们需要考虑 ,这样我们转化一下就是 ,容易发现我们需要乘上 qpow(fu, n - (c * m - b - 1) / a)。
那么我们就可以得到最后的 AsGcd 代码为:
1 2 3 4 5 6 7 8 9 10 11 12
Node AsGcd(int a, int b, int c, int n, Node fu, Node fr) { b %= c; if (a >= c) returnAsGcd(a % c, b, c, n, fu, qpow(fu, a / c) * fr); LL m = (LL(a) * n + b) / c;// y = (cx - b - 1) / a if (m == 0) returnqpow(fr, n);// all is fr std::swap(fu, fr); returnqpow(fu, (c - b - 1) / a) * fr // solving x in [0, 1] * AsGcd(c, c - b - 1, a, m - 1, fu, fr) // solving x in (1, m] * qpow(fu, n - (c * m - b - 1) / a) // solving x in [m, m + 1), notice that y_max = n ; }
类似欧几里得算法,得到时间复杂度 ,不过常数比较大。
最后递归的时候,注意到 0 是被包含进入答案的,所以递归前,我们要先乘上 qpow(fu, b / c) * fr。
Node AsGcd(LL a, LL b, LL c, LL n, Node fu, Node fr) { b %= c; if (a >= c) returnAsGcd(a % c, b, c, n, fu, qpow(fu, a / c) * fr); LL m = ((s128) a * n + b) / c; if (m == 0) returnqpow(fr, n); std::swap(fu, fr); auto ret = qpow(fu, (c - b - 1) / a) * fr * AsGcd(c, c - b - 1, a, m - 1, fu, fr) * qpow(fu, n - ((s128) c * m - b - 1) / a); return ret; }
Node qpow(Node a, LL k) { assert(k >= 0); Node res(f0); for (; k; k >>= 1, a = a * a) if (k & 1) res = res * a; return res; }
Node AsGcd(LL a, LL b, LL c, LL n, Node fu, Node fr) { b %= c; if (a >= c) returnAsGcd(a % c, b, c, n, fu, qpow(fu, a / c) * fr); LL m = ((s128) a * n + b) / c; if (m == 0) returnqpow(fr, n); std::swap(fu, fr); auto ret = qpow(fu, (c - b - 1) / a) * fr * AsGcd(c, c - b - 1, a, m - 1, fu, fr) * qpow(fu, n - ((s128) c * m - b - 1) / a); return ret; }
intmain() { LL a, b, c, l; std::cin >> a >> c >> b >> l >> n; for (int i = 0; i < n; ++ i) I[i][i] = 1; for (int i = 0; i < n; ++ i) for (int j = 0; j < n; ++ j) scanf("%d", &A[i][j]); for (int i = 0; i < n; ++ i) for (int j = 0; j < n; ++ j) scanf("%d", &B[i][j]); Node fu{I, B, {}}, fr{A, I, A}; f0 = {I, I, {}}; auto res = (qpow(fu, b / c) * AsGcd(a, b, c, l, fu, fr)).ans; for (int i = 0; i < n; ++ i, puts("")) for (int j = 0; j < n; ++ j) printf("%d ", res[i][j]); return0; }
Related Issues not found
Please contact @mydcwfy to initialize the comment