类欧几里得学习笔记

  • 类欧几里得可以等价于求 (y=(ax+b)/c) 这条直线和 (x=0,y=0,x=n) 围成的直角梯形内整点个数

前置芝士:

  • img

  • 用途:快速求出以下式子的值

    (displaystyle f(a,b,c,n)=sum_{i=0}^nlfloor frac{ai+b}{c} floor)
    (displaystyle g(a,b,c,n)=sum_{i=0}^n ilfloor frac{ai+b}{c} floor)
    (displaystyle h(a,b,c,n)=sum_{i=0}^nlfloor frac{ai+b}{c} floor^2)

    (记 (m=lfloor frac{an+b}{c} floor))

推柿子

  • (f)

    1. (a>c or b>c)

      (f(a,b,c,n)=f(amod c,bmod c,c,n)+frac{n(n+1)}{2}lfloorfrac{a}{c} floor+(n+1)lfloorfrac{b}{c} floor)

    2. (a<c and b<c)

      [displaystyle f(a,b,c,n)=sum_{i=0}^nsum_{j=1}^m[jle lfloor frac{ai+b}{c} floor] \ =sum_{i=0}^nsum_{j=0}^{m-1}[j+1le lfloor frac{ai+b}{c} floor] \ =sum_{i=0}^nsum_{j=0}^{m-1}[cj+c-ble ai] \ =sum_{i=0}^nsum_{j=0}^{m-1}[cj+c-b-1< ai] \ =sum_{i=0}^nsum_{j=0}^{m-1}[frac{cj+c-b-1}{a}<i] \ =sum_{j=0}^{m-1} n-lfloorfrac{cj+c-b-1}{a} floor \ =n*m-f(c,c-b+1,a,m-1) ]

  • (g)

    1. (a>c or b>c)

      (g(a,b,c,n)=g(amod c,bmod c,c,n)+frac{n(n+1)(2n+1)}{6}lfloorfrac{a}{c} floor+frac{n(n+1)}{2}lfloorfrac{b}{c} floor)

    2. (a<c and b<c)

      [displaystyle g(a,b,c,n)=sum_{i=0}^nisum_{j=1}^m[jle lfloor frac{ai+b}{c} floor] \ =sum_{i=0}^nisum_{j=0}^{m-1}[j+1le lfloor frac{ai+b}{c} floor] \ =sum_{i=0}^nisum_{j=0}^{m-1}[cj+c-ble ai] \ =sum_{i=0}^nisum_{j=0}^{m-1}[cj+c-b-1< ai] \ =sum_{i=0}^nisum_{j=0}^{m-1}[frac{cj+c-b-1}{a}<i] \ 由于 i 的取值是一个等差数列,首项为 lfloorfrac{cj+c-b-1}{a} floor+1 末项为 n \ =sum_{j=0}^{m-1}frac{(n-lfloorfrac{cj+c-b-1}{a} floor)(n+lfloorfrac{cj+c-b-1}{a} floor+1)}{2} \ =frac{1}{2}sum_{j=0}^{m-1}(n(n+1)-lfloorfrac{cj+c-b-1}{a} floor-lfloorfrac{cj+c-b-1}{a} floor^2) \ =frac{mn(n+1)-f(c,c-b+1,a,m-1)-h(c,c-b+1,a,m-1)}{2} ]

  • (h)

    1. (a>c or b>c)

      (h(a,b,c,n)=h(amod c,bmod c,c,n)\+frac{n(n+1)(2n+1)}{6}lfloorfrac{a}{c} floor^2+(n+1)lfloorfrac{b}{c} floor^2\+2lfloorfrac{b}{c} floor f(amod c,bmod c,c,n)+2lfloorfrac{a}{c} floor g(amod c,bmod c,c,n)+lfloorfrac{b}{c} floorlfloorfrac{a}{c} floor n(n+1))

    2. (a<c and b<c)

      为了方便计算我们,将 (n^2) 转化一下,(n^2=2*frac{n(n+1)}{2}-n=-n+2sum_{i=0}^ni)

    [displaystyle h(a,b,c,n)=sum_{i=0}^n(-lfloor{frac{ai+b}{c}} floor+2sum_{j=0}^{lfloor{frac{ai+b}{c}} floor}j) \ 将括号内部的两个式子分开计算 \ =2sum_{j=0}^{m-1}j+1sum_{i=0}^n[lfloor{frac{ai+b}{c}} floorge j+1]-f(a,b,c,n) \ 不想推了/kk \ 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) ]

代码:

这式子能给我写吐了/ee

#include<bits/stdc++.h>

using namespace std;

namespace zzc
{
    long long read()
    {
        long long x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
        return x*f;
    }

    const long long mod = 998244353;
    const long long inv2 = 499122177;
    const long long inv6 = 166374059;

    struct node
    {
        long long f,g,h;
        node(){}
        node(long long f,long long g,long long h){}
    };

	node solve(long long a,long long b,long long c,long long n)
    {
        node ans,tmp;
        if(!a)
        {
        	n%=mod;
        	ans.f=(n+1)*(b/c)%mod;
       		ans.g=(b/c)*n%mod*(n+1)%mod*inv2%mod;
      		ans.h=(n+1)*(b/c)%mod*(b/c)%mod;
        	return ans;
        }
        if(a>=c||b>=c)
        {
            ans=solve(a%c,b%c,c,n);
			n%=mod;
            ans.h=( ans.h
                    +1ll*n*(n+1)%mod*(2*n%mod+1)%mod*inv6%mod*(a/c)%mod*(a/c)%mod
                    +(n+1)%mod*(b/c)%mod*(b/c)%mod
                    +2*(b/c)%mod*ans.f%mod
                    +2*(a/c)%mod*ans.g%mod
                    +n*(n+1)%mod*(a/c)%mod*(b/c)%mod
                  ) %mod;
            ans.f=(ans.f+n*(n+1)%mod*inv2%mod*(a/c)%mod+(n+1)*(b/c)%mod)%mod;
            ans.g=(ans.g+n*(n+1)%mod*(2*n+1)%mod*inv6%mod*(a/c)%mod+n*(n+1)%mod*inv2%mod*(b/c))%mod;
            return ans;
        }
        long long m=(a*n+b)/c;
        tmp=solve(c,c-b-1,a,m-1);
        n%=mod;m%=mod;
        ans.f=(n*m%mod-tmp.f+mod)%mod;
        ans.g=(m*n%mod*(n+1)%mod-tmp.f+mod-tmp.h+mod)%mod*inv2%mod;
        ans.h=(m*n%mod*(m+1)%mod-2*((tmp.f+tmp.g)%mod)%mod+mod-ans.f+mod)%mod;
        return ans;
    }

    void work()
    {
        long long t,n,a,b,c;
        node ans;
        t=read();
        while(t--)
        {
            n=read();a=read();b=read();c=read();
            ans=solve(a,b,c,n);
            printf("%lld %lld %lld
",ans.f,ans.h,ans.g);
        }
    }


}

int main()
{
    zzc::work();
    return 0;
}
原文地址:https://www.cnblogs.com/youth518/p/14295072.html