• 类欧几里得算法


    类欧几里得算法

    • By Winniechen

    一种用来快速求某些带有特殊性质的式子的和,一般复杂度为$O(log n)$,有些特殊时刻,需要用到$gcd$,因此为$O(log^2 n)$

    第一类

    $f(a,b,c,n)=sumlimits_{i=0}^nlfloorfrac{a imes i+b}{c} floor$

    显然,若$age c$,那么:​
    $$
    f(a,b,c,n)=sumlimits_{i=0}^nlfloorfrac{(c imes k+t) imes i+b}{c} floor =sumlimits_{i=0}^nk imes i+lfloorfrac{t imes i+b}{c} floor =frac{i imes (i+1) imes k}{2}+sumlimits_{i=0}^nlfloorfrac{t imes i+b}{c} floor =frac{i imes (i+1) imes k}{2}+f(t,b,c,n)
    $$

    同样,若$bge c$,那么:$f(a,b,c,n)=sumlimits_{i=0}^n{lfloorfrac{a imes i+c imes k+t}{c} floor}=f(a,t,c,n)+k imes n$

    因此,我们可以将上面两种情况转化为下面的这种:

    $f(a,b,c,n),a< c,b<c$

    $f(a,b,c,n)=sumlimits_{i=0}^nlfloorfrac{a imes i+b}{c} floor=sumlimits_{i=0}nsumlimits_{j=1}m[lfloorfrac{a imes i+b}{c} floorge j],(m=frac{a imes n+b}{c})$
    $$
    f(a,b,c,n) \ =sumlimits_{i=0}nsumlimits_{j=0}{m-1}{[a imes i > j imes c+c-b-1]} \ =sumlimits_{i=0}nsumlimits_{j=0}{m-1}[i> frac{j imes c+c-b-1}{a}] \ = sumlimits_{j=0}^{m-1}n-lfloorfrac{c imes j-b+c-1}{a} floor \ = n imes m-f(c,c-b-1,a,m-1)​
    $$

    显然,对于项:$a,c$,经过了类似$gcd$的$a=c,c=a%c$

    因此,复杂度得以保证。

    第二类

    $g(a,b,c,n)=sumlimits_{i=0}^ni imes lfloorfrac{a imes i+b}{c} floor$

    类似前面的,推出$a,bge c$的情况。

    $g(a,b,c,n)=frac{n imes (n + 1) imes (2 imes n+1)}{6} k_a+frac{n imes (n+1)}{2}k_b+g(t_a,t_b,c,n)$

    $g(a,b,c,n)=sumlimits_{i=0}^ni imes lfloorfrac{a imes i+b}{c} floor=sumlimits_{i=0}nisumlimits_{j=1}m[lfloorfrac{a imes i+n}{c} floorge j]$,$m$同上

    发现后面的同上,所有我就跳过几步.jpg
    $$
    g(a,b,c,n)\ =sumlimits_{i=0}nisumlimits_{j=0}{m-1}[i>lfloorfrac{c imes j+c-b-1}{a} floor ] \ =sumlimits_{j=0}^{m-1} frac{n imes (n+1)}{2}-frac{x imes (x+1)}{2}(x=lfloorfrac{c imes j+c-b-1}{a} floor) \ =frac{n imes (n+1) imes m+sumlimits_{j=0}{m-1}x+x2}{2}\ = frac{n imes (n+1) imes m-f(c,c-b-1,a,m-1)-h(c,c-b-1,a,m-1)}{2}
    $$

    $h(a,b,c,n)=sumlimits_{i=0}^n lfloorfrac{a imes i+b}{c} floor ^2$,这个马上介绍...

    但是显然,这个$g(a,b,c,d)$就只差$h(a,b,c,d)$了,其他都没有问题,都可以在$log n$内解决

    第三类

    $h(a,b,c,n)=sumlimits_{i=0}^n lfloorfrac{a imes i+b}{c} floor ^2$

    同样类似上面的那个...
    $$
    h(a,b,c,n)= (a/c)^2n(n+1)(2n+1)/6+ (b/c)^2(n+1)+(a/c)(b/c)n(n+1)+ h(a%c,b%c,c,n)+2(a/c)g(a%c,b%c,c,n)+ 2(b/c)f(a%c,b%c,c,n)$​
    $$
    其实也没啥,就是麻烦了点...

    就是需要稍微构造一下,因为正常推的话,显然是不能推的...

    $n^2=2 imesfrac{n imes (n+1)}{2}-n=2(sumlimits_{i=0}^n i) -n$

    $h(a,b,c,n)=sumlimits_{i=0}n2sumlimits_{j=1}xj-f(a,b,c,n)$

    $h(a,b,c,n)=sumlimits_{j=0}^{m-1}2 imes (j+1)sumlimits_{i=0}^n[lfloorfrac{a imes i+b}{c} floor ge j+1]-f(a,b,c,n)$

    $h(a,b,c,n)=2sumlimits_{j=0}^{m-1}(j+1) imes(n- lfloorfrac{c imes j+c-b-1}{a}])-f(a,b,c,n)$
    $$
    h(a,b,c,n)= n imes m imes (m+1) - 2 imes g(c,c-b-1,a,m-1) - 2 imes f(c,c-b-1,a,m-1) - f(a,b,c,n)
    $$
    完事了!

    第一种,难写难调跑得慢...(并且复杂度多了一个$log$

    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <queue>
    #include <iostream>
    #include <bitset>
    #include <map>
    using namespace std;
    #define ll long long
    #define mod 998244353
    #define inv2 499122177
    #define inv6 166374059
    struct node
    {
    	ll a,b,c,d;
    	node(){}
    	node(ll x,ll y,ll z,ll w){a=x,b=y,c=z,d=w;}
    	bool operator < (const node &t) const {return a==t.a?(t.b==b?(t.c==c?d<t.d:c<t.c):b<t.b):a<t.a;}
    };
    map<node ,ll >F,G,H;
    ll f(ll n,ll a,ll b,ll c)
    {
    	if(F.find(node(n,a,b,c))!=F.end())return F[node(n,a,b,c)];
    	if(b>=c)return F[node(n,a,b,c)]=(f(n,a,b%c,c)+(b/c)*(n+1)%mod)%mod;
    	if(a>=c)return F[node(n,a,b,c)]=(f(n,a%c,b,c)+(a/c)*(n*(n+1)%mod*inv2%mod)%mod)%mod;
    	if(!a)return 0;
    	ll m=(a*n+b)/c;return F[node(n,a,b,c)]=(n*m%mod-f(m-1,c,c-b-1,a))%mod;
    }
    ll g(ll n,ll a,ll b,ll c);
    ll h(ll n,ll a,ll b,ll c);
    ll g(ll n,ll a,ll b,ll c)
    {
    	if(G.find(node(n,a,b,c))!=G.end())return G[node(n,a,b,c)];
    	if(a>=c)return G[node(n,a,b,c)]=(g(n,a%c,b,c)+(a/c)*n%mod*(n+1)%mod*(n*2+1)%mod*inv6)%mod;
    	if(b>=c)return G[node(n,a,b,c)]=(g(n,a,b%c,c)+(b/c)*n%mod*(n+1)%mod*inv2)%mod;
    	if(!a)return 0;
    	ll m=(a*n+b)/c;return G[node(n,a,b,c)]=(n*(n+1)%mod*m%mod-f(m-1,c,c-b-1,a)+mod-h(m-1,c,c-b-1,a)+mod)*inv2%mod;
    }
    ll h(ll n,ll a,ll b,ll c)
    {
    	if(H.find(node(n,a,b,c))!=H.end())return H[node(n,a,b,c)];
    	if(a>=c||b>=c)
    		return  H[node(n,a,b,c)]=((a/c)*(a/c)%mod*n%mod*(n+1)%mod*(n*2+1)%mod*inv6%mod+
    				(b/c)*(b/c)%mod*(n+1)%mod+(a/c)*(b/c)%mod*n%mod*(n+1)%mod+
    				h(n,a%c,b%c,c)%mod+2*(a/c)%mod*g(n,a%c,b%c,c)%mod+
    				2*(b/c)*f(n,a%c,b%c,c)%mod)%mod;
    	if(!a)return 0;
    	ll m=(a*n+b)/c;
    	return H[node(n,a,b,c)]=((n*m%mod*(m+1)%mod-2*g(m-1,c,c-b-1,a)-2*f(m-1,c,c-b-1,a))%mod-f(n,a,b,c)+mod+mod)%mod;
    }
    int main()
    {
    	int T;scanf("%d",&T);
    	while(T--)
    	{
    		ll a,b,c,n;scanf("%lld%lld%lld%lld",&n,&a,&b,&c);
    		printf("%lld %lld %lld
    ",(f(n,a,b,c)+mod)%mod,(h(n,a,b,c)+mod)%mod,(g(n,a,b,c)+mod)%mod);
    		F.clear();G.clear();H.clear();
    	}
    }
    // TLE 
    // 非常慢.jpg
    

    第二种,好写好调跑得快...

    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <queue>
    #include <iostream>
    #include <bitset>
    using namespace std;
    #define ll long long
    #define mod 998244353
    #define inv2 499122177
    #define inv6 166374059
    struct node
    {
    	ll f,g,h;
    	node(){f=0,g=0,h=0;}
    	node(ll a,ll b,ll c){f=a,g=b,h=c;}
    	void print(){printf("%lld %lld %lld
    ",f,h,g);}
    };
    node solve(ll n,ll a,ll b,ll c)
    {
    	if(!a)return node((b/c)*(n+1)%mod,(n*(n+1)%mod*inv2)%mod*(b/c)%mod,(b/c)*(b/c)%mod*(n+1)%mod);
    	node ret=node();
    	if(a>=c||b>=c)
    	{
    		ll t1=a/c,t2=b/c,s1=n*(n+1)%mod*inv2%mod,s2=n*(n+1)%mod*(2*n+1)%mod*inv6%mod;
    		node tmp=solve(n,a%c,b%c,c);
    		ret.f=(tmp.f+(n+1)*t2%mod+s1*t1%mod)%mod;
    		ret.g=(tmp.g+s1*t2%mod+s2*t1%mod)%mod;
    		ret.h=(t1*t1%mod*s2%mod+(n+1)*t2%mod*t2%mod+2*t1*t2%mod*s1%mod+2*t1*tmp.g%mod+2*t2*tmp.f%mod+tmp.h)%mod;
    		return ret;
    	}
    	ll m=(a*n+b)/c;node tmp=solve(m-1,c,c-b-1,a);
    	ret.f=(n*m%mod-tmp.f+mod)%mod;
    	ret.g=((n*(n+1)%mod*m%mod-tmp.f-tmp.h)%mod+mod)*inv2%mod;
    	ret.h=((n*m%mod*m%mod-tmp.g*2%mod-tmp.f)%mod+mod)%mod;
    	return ret;
    }
    ll a,b,c,n;
    int main(){int T;scanf("%d",&T);while(T--)scanf("%lld%lld%lld%lld",&n,&a,&b,&c),solve(n,a,b,c).print();}
    
  • 相关阅读:
    非父子组件通信
    vue中的导航守卫
    vue中做出购物车的功能
    vuex初使用(写的当然是最简单的应用啦)
    封装了一个电商放大镜移入放大的功能,适用于VUE
    moment.js插件的简单上手使用
    Vue中如何将数据传递到下一个页面(超级简单哒)
    java Math
    java Arrays
    java static
  • 原文地址:https://www.cnblogs.com/Winniechen/p/10649706.html
Copyright © 2020-2023  润新知