zoukankan      html  css  js  c++  java
  • 类欧几里得算法

    这个板子是真(TM)毒。心脑血管疾病患者慎入


    传送门

    总之先来康柿子,给定非负整数(n,a,b,c),求下面三个柿子(这里的(g,h)顺序好像和题目颠倒了......问题不大):

    [f(a,b,c,n) = sumlimits_{i = 0}^{n} leftlfloor frac{ai + b}{c} ight floor ]

    [g(a,b,c,n) = sumlimits_{i = 0}^{n} i leftlfloor frac{ai + b}{c} ight floor ]

    [h(a,b,c,n) = sumlimits_{i = 0}^{n} leftlfloor frac{ai + b}{c} ight floor ^ 2 ]

    并输出对(998244353)取模的结果,保证(0 le n,a,b,c le 10^9, c ot= 0)


    (f(a,b,c,n)):

    由于(a)非负,所以(leftlfloor frac{ai + b}{c} ight floor)对于(i)是递增的,为了方便,下面令(d(i) = leftlfloor frac{ai + b}{c} ight floor)

    换句话说,(d(i))的最大值就是(d(n)),我们令(m = d(n))

    那么就有

    [d(i) = sumlimits_{j = 1}^{m} left[ j le d(i) ight] ]

    (j = j-1)(为什么呢?等会就知道了。)

    [d(i) = sumlimits_{j = 0}^{m - 1} left[ j+1 le d(i) ight] ]

    然后把取整符号去掉

    [d(i) = sumlimits_{j = 0} ^ {m-1} left[ j+1 le frac{ai + b}{c} ight] ]

    我们还能进一步化简中括号里的柿子

    [j + 1 le frac{ai + b}{c} Leftrightarrow cj + c - b le ai ]

    这里直接两边除以(a)?然而并不能。因为除以(a)后我们肯定会再把取整符号填上去,但(frac{cj + c - b}{a} le i)并不能说明(leftlfloor frac{cj + c - b}{a} ight floor le i)

    所以我们还是要把两边减一再变

    [cj + c - b - 1 < ai Leftrightarrow frac{cj + c - b - 1}{a} < i Leftrightarrow leftlfloor frac{cj + c - b - 1}{a} ight floor < i ]

    再带回(d(i)),同时令(alpha = alpha(j) = leftlfloor frac{cj + c - b - 1}{a} ight floor)

    [d(i) = sumlimits_{j = 0}^{m - 1} left[ i > alpha ight] ]

    回到原式

    [egin{aligned} f(a,b,c,n) &= sumlimits_{i = 0}^{n} d(i) \ &= sumlimits_{i = 0}^{n} sumlimits_{j = 0}^{m - 1} left[ i > alpha ight] end{aligned} ]

    交换求和顺序再来颓柿子

    [egin{aligned} f(a,b,c,n) &= sumlimits_{j = 0} ^ {m - 1} sumlimits_{i = 0} ^ {n} [i > alpha] \ &= sumlimits_{j = 0}^{m - 1} { (n+1) - (alpha + 1) } \ &= sumlimits_{j = 0} ^ {m - 1} { n - alpha} \ &= nm - sumlimits_{j = 0}^{m - 1} alpha end{aligned} ]

    后面的(sumlimits_{j = 0}^{m - 1} alpha)也就是(f(c, c -b - 1, a, m - 1)),于是(上面让(j)(0)开始就是为了这一步)

    [f(a,b,c,n) = nm - f(c,c-b-1,a,m-1) ]

    没了?并没有......

    发现如果(c - b - 1 < 0)的话这个柿子就炸了......

    考虑让(b)(c)取模,顺便也把(a)带走((a = 0)也是边界)。

    [egin{aligned}d(i) &= leftlfloor frac{ai + b}{c} ight floor \&= leftlfloor frac{(leftlfloor frac{a}{c} ight floor c + a mod c)i + leftlfloor frac{b}{c} ight floor c + b mod c}{c} ight floorend{aligned} ]

    注意到(leftlfloor frac{a}{c} ight floor c i)(leftlfloor frac{b}{c} ight floor c)都是整数,且有约数(c),直接提出来

    [d(i) = leftlfloor frac{a}{c} ight floor i + leftlfloor frac{b}{c} ight floor + leftlfloor frac{(a mod c) i + b mod c}{c} ight floor ]

    于是

    [f(a,b,c,n) = frac{n(n+1)}{2}leftlfloor frac{a}{c} ight floor + (n+1)leftlfloor frac{b}{c} ight floor + f(a mod c, b mod c, c, n) ]

    这样就可以递归算了,边界就是(a = 0)

    [f(a,b,c,n) = egin{cases}nm - f(c, c-b-1, a, m - 1) quad (a < c and b < c) \frac{n(n+1)}{2}leftlfloor frac{a}{c} ight floor + (n+1)leftlfloor frac{b}{c} ight floor + f(a mod c, b mod c, c, n) quad (a ge c or b ge c) \(n+1) leftlfloor frac{b}{c} ight floor quad (a = 0)end{cases} ]

    时间复杂度:

    观察(a)位置上和(c)位置上的数,第一次是((a,c))(不放设(a < c)),第(2)次会变为((c,a)),第三次((c mod a, a))然后再交换位置,再取模。这不就是(gcd)吗?于是复杂度就是(gcd)的复杂度(*2)


    (g(a,b,c,n))

    类似上面的(f),我们也照这个样子推导(g)。(一些定义和上面类似)。

    (a ge c or b ge c)

    [egin{aligned}g(a,b,c,n) &= sumlimits_{i = 0}^{n} i cdot d(i)end{aligned} ]

    (d(i))展开

    [egin{aligned}g(a,b,c,n)&= sumlimits_{i = 0} ^ n i cdot (leftlfloor frac{a}{c} ight floor i + leftlfloor frac{b}{c} ight floor + leftlfloor frac{(a mod c)i + b mod c}{c} ight floor) \&= sumlimits_{i = 0} ^ n leftlfloor frac{a}{c} ight floor i^2 + leftlfloor frac{b}{c} ight floor i + i cdot leftlfloor frac{(a mod c)i + b mod c}{c} ight floor \&= frac{1}{6}n(n+1)(2n+1)leftlfloor frac{a}{c} ight floor + frac{1}{2}n(n+1)leftlfloor frac{b}{c} ight floor + g(a mod c, b mod c, c, n)end{aligned} ]

    (a < c and b < c)

    [egin{aligned}g(a,b,c,n)&= sumlimits_{i = 0}^{n} i cdot d(i) \&= sumlimits_{i = 0} ^ n i sumlimits_{j = 0}^{m - 1}[i > alpha] \&= sumlimits_{j = 0} ^ {m-1} sumlimits_{i = 0}^{n} i cdot [i > alpha]end{aligned} ]

    第二个(sum)就是对(alpha+1...n)这些整数求和,直接套公式

    [egin{aligned}g(a,b,c,n)&= sumlimits_{j = 0}^{m - 1} frac{1}{2}(n-alpha)(n+alpha+1) \&= frac{1}{2} sumlimits_{j = 0}^{m - 1} n^2 + nalpha + n - nalpha - alpha^2 - alpha \&= frac{1}{2}left[ mn(n+1) - h(c, c-b-1, a, m-1) - f(c, c-b-1, a,m-1) ight]end{aligned} ]

    这里用到了(f)(h)

    边界就是(a = 0)时,(g = frac{1}{2}n(n+1)leftlfloor frac{b}{c} ight floor)

    发现(g)也是一个类似于(f)的递归过程,可以和(f)放到一起算。


    (h(a,b,c,n))

    感觉平方项很难通过枚举值算贡献的方法化简......

    怎么办呢?

    考虑到(1+2+...+n = frac{1}{2}n(n+1)),那么(n^2 = 2left(sumlimits_{k = 0}^{n}k ight) - n)

    带到(d(i))里再带回原柿就是

    [egin{aligned}h(a,b,c,n)&= sumlimits_{i = 0}^{n} d(i)^2 \&= sumlimits_{i = 0}^{n} 2 left( sumlimits_{k = 0} ^ {d(i)} k ight)-d(i) \&= left( 2 sumlimits_{i = 0} ^ n sumlimits_{k = 0} ^ {d(i)}k ight) - f(a,b,c,n)end{aligned} ]

    考虑怎么求(sumlimits_{i = 0} ^ n sumlimits_{k = 0} ^ {d(i)}k),同样的,让(j)代替(k),并从(0)跑到(m-1),然后交换求和顺序

    [sumlimits_{j = 0} ^ {m - 1} sumlimits_{i = 0} ^ {n} [j +1 le d(i)] cdot (j+1) ]

    中括号里我们已经化简过了,再把(j+1)提到外面

    [egin{aligned}sumlimits_{j =0}^{m-1} (j+1) sumlimits_{i = 0}^{n} [i>alpha]&= sumlimits_{j = 0}^{m-1}(j+1)(n-alpha) \&= sumlimits_{j = 0}^{m - 1} n(j+1) - j cdot alpha - alpha \&= frac{1}{2} m(m+1)n - g(c, c-b-1, a, m-1) - f(c, c-b-1, a, m-1)end{aligned} ]

    所以(h(a,b,c,n) = m(m+1)n - 2g(c,c-b-1,a,m-1) - 2f(c,c-b-1,a,m-1) - f(a,b,c,n))

    取模的话暴力三元完平展开就好了

    [h(a,b,c,n) = h(a mod c, b mod c, c, n) + 2 leftlfloor frac{b}{c} ight floor f(a mod c, b mod c, c, n) + 2leftlfloor frac{a}{c} ight floor g(a mod c, b mod c, c, n) + frac{1}{6}n(n+1)(2n+1) leftlfloor frac{a}{c} ight floor ^ 2 + (n+1) leftlfloor frac{b}{c} ight floor^2 + n(n+1) leftlfloor frac{a}{c} ight floor leftlfloor frac{b}{c} ight floor ]

    边界就是(a = 0)(h(a,b,c,n) = leftlfloor frac{b}{c} ight floor ^ 2(n+1))(h)也可以和(f,g)放到一起算。

    总复杂度是(gcd)的复杂度。


    (Code):

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    inline ll read() {
    	char ch; ll x = 0; int f = 1; while (!isdigit(ch = getchar())) f = ch=='-' ? -f : f;
    	while (isdigit(ch)){ x = x*10 + ch - '0'; ch = getchar(); } return x * f;
    }
    
    const int P = 998244353, i2 = 499122177, i6 = 166374059;
    void update(ll &x, ll y) {
    	x += y; if (x >= P) x -= P;
    }
    inline ll s1(ll n) {
    	n %= P; return n % P * (n+1) % P * i2 % P;
    }
    inline ll s2(ll n) {
    	n %= P; return n % P * (n+1) % P * (2ll*n%P + 1) % P * i6 % P;
    }
    inline ll sqr(ll x) {
    	return 1ll * x * x % P;
    }
    
    #define chk(x) assert(0<=(x) && (x)<P)
    
    void euclid(ll a, ll b, ll c, ll n, ll &f, ll &g, ll &h) {
    	ll ac = a/c, bc = b/c, m = 1ll * (1ll*a*n + b) / c;
    	if (a == 0) {
    		f = 1ll * bc * (n + 1) % P, g = 1ll * bc * s1(n) % P;
    		h = 1ll * sqr(bc) * (n + 1) % P;
    		return;
    	}
    	ll f1, g1, h1;
    	if (a >= c || b >= c) {
    		euclid(a % c, b % c, c, n, f1, g1, h1);
    		f = g = h = 0;
    		update(f, 1ll * s1(n) * ac % P), update(f, 1ll * bc * (n+1) % P), update(f, f1);
    		update(g, 1ll * s2(n) * ac % P), update(g, 1ll * s1(n) * bc % P), update(g, g1);
    		update(h, 1ll * s2(n) * sqr(ac) % P), update(h, 1ll * (n+1) * sqr(bc) % P);
    		update(h, h1), update(h, 2ll * ac * g1 % P);
    		update(h, 1ll * n * (n+1) % P * ac % P * bc % P);
    		update(h, 2ll * bc * f1 % P);
    		return;
    	}
    	euclid(c, c-b-1, a, m-1, f1, g1, h1);
    	f = g = h = 0;
    	update(f, 1ll * n * m % P), update(f, P - 1ll * f1 % P);
    	update(g, 1ll * n % P * (n+1) % P * m % P);
    	update(g, P - 1ll * f1 % P), update(g, P - 1ll * h1 % P), g = g * i2 % P;
    	update(h, 1ll * m * (m+1) % P * n % P), update(h, P - 2ll * g1 % P);
    	update(h, P - 2ll * f1 % P), update(h, P - f);
    }
    
    int main(){
    	for (int T = read(); T; T--) {
    		ll n = read(), a = read(), b = read(), c = read(), f, g, h;
    		euclid(a, b, c, n, f, g, h);
    		printf("%lld %lld %lld
    ", f, h, g);
    	}
    	return 0;
    }
    

    一般形式的话......估计这辈子都学不动了(QwQ)

  • 相关阅读:
    poj 2728 Desert King
    uva 439 Knight Moves
    hdu 1875 畅通工程再续
    scau实验题 8600 骑士周游问题(有障碍物)
    scau实验题 8596 Longest Ordered Subsequence
    poj 1679 The Unique MST
    uva 527 Oil Deposits
    poj 2533 Longest Ordered Subsequence
    .net 程序员 java 开发入门
    Collation conflict occur at operation on User define funtion & table's column
  • 原文地址:https://www.cnblogs.com/wxq1229/p/12215748.html
Copyright © 2011-2022 走看看