Introduced
solve
Seeking f (a, b, c, n) with O (logn) algorithm.
We've seen this formula and formula are not the same look. With rounding down of the formulas easy to think of number theory block, but the block number theory seems not apply to this sum. But we can do some preprocessing.
If a> = c or b> = c, means may be a, b to c modulo a simplified problem:
The problem has returned a <situation <c && b c, and the expression conditions for i <n, contributions to the floor ((a * i + b ) / c), this time we will contribute to the condition to do the conversion, the contribution becomes form a new sub-conditions:
Now more than a variable j, i since the contribution of poor demand, then we can go to seek contribution j, in which case we restrict the transfer type, and where n in the above limit i upper bound, but i limit j upper bound. To engage j , j placed on the first contribution formula yard, forced by n limit j upper bound
The j <floor ((a * i + b) / c) for simplification stars
This is a recursive formula. And you find a, c numerator and denominator for a location, and can repeat the process. First modulo recursively. This is a toss of the division process, which is named after the class Euclidean algorithm.
Easy to find the time complexity is O (log (n-)) .
Spread
begging
For the function g
As before, modulo, as Σi * i = (n + 1) * (2 * n + 1) * n / 6, it is
For the function h
Also first modulo
Because the three functions intersect, so the template is obtained together
#include <bits/stdc++.h> #define int long long using namespace std; const int P = 998244353; int i2 = 499122177, i6 = 166374059; struct data { data() { f = g = h = 0; } int f, g, h; }; // 三个函数打包 data calc(int n, int a, int b, int c) { int ac = a / c, bc = b / c, m = (a * n + b) / c, n1 = n + 1, n21 = n * 2+ . 1 ; Data D; IF (A == 0 ) // iteration to the bottom { DF = N1 * BC% P; DG = BC% * n-P * N1 * I2% P% P; DH = BC * BC% N1% * P P; return D; } IF (A> B = C ||> = C) // modulo { DF = n-P * N1 * I2% AC% P% P * BC * N1 +% P; DG = AC * n-% P * N1% P * N21% P * I6% P + BC * n-% P * N1% P * I2% P; DH = AC * AC% P * n-% P * N1% P * n21% P * i6% P + bc * bc % P * n1 % P + ac * bc % P * n % P * n1 % P; d.f %= P, d.g %= P, d.h %= P; data e = calc(n, a % c, b % c, c); // 迭代 d.h += e.h + 2 * bc % P * e.f % P + 2 * ac % P * e.g % P; d.g += e.g, d.f += e.f; d.f %= P, d.g %= P, d.h %= P; return d; } data e = calc(m - 1, c, c - b - 1, a); d.f = n * m % P - e.f, d.f = (d.f % P + P) % P; d.g = m * n % P * n1 % P - e.h - e.f, d.g = (d.g * i2 % P + P) % P; d.h = n * m % P * (m + 1) % P - 2 * e.g - 2 * e.f - d.f; d.h = (d.h % P + P) % P; return d; } int T, n, a, b, c; signed main() { scanf("%lld", &T); while (T--) { scanf("%lld%lld%lld%lld", &n, &a, &b, &c); data ans = calc(n, a, b, c); printf("%lld %lld %lld\n", ans.f, ans.h, ans.g); } return 0; }
The main contribution to learn to use the Conditional Sum transfer method, and further simplification of n squared, there are three templates.