类欧几里得学习笔记

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

前置芝士:

  • img

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

    \(\displaystyle f(a,b,c,n)=\sum_{i=0}^n\lfloor \frac{ai+b}{c}\rfloor\)
    \(\displaystyle g(a,b,c,n)=\sum_{i=0}^n i\lfloor \frac{ai+b}{c}\rfloor\)
    \(\displaystyle h(a,b,c,n)=\sum_{i=0}^n\lfloor \frac{ai+b}{c}\rfloor^2\)

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

推柿子

  • \(f\)

    1. \(a>c\ or \ b>c\)

      \(f(a,b,c,n)=f(a\mod c,b\mod c,c,n)+\frac{n(n+1)}{2}\lfloor\frac{a}{c}\rfloor+(n+1)\lfloor\frac{b}{c}\rfloor\)

    2. \(a<c\ and b<c\)

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

  • \(g\)

    1. \(a>c\ or \ b>c\)

      \(g(a,b,c,n)=g(a\mod c,b\mod c,c,n)+\frac{n(n+1)(2n+1)}{6}\lfloor\frac{a}{c}\rfloor+\frac{n(n+1)}{2}\lfloor\frac{b}{c}\rfloor\)

    2. \(a<c\ and b<c\)

      \[\displaystyle g(a,b,c,n)=\sum_{i=0}^ni\sum_{j=1}^m[j\le \lfloor \frac{ai+b}{c}\rfloor] \\ =\sum_{i=0}^ni\sum_{j=0}^{m-1}[j+1\le \lfloor \frac{ai+b}{c}\rfloor] \\ =\sum_{i=0}^ni\sum_{j=0}^{m-1}[cj+c-b\le ai] \\ =\sum_{i=0}^ni\sum_{j=0}^{m-1}[cj+c-b-1< ai] \\ =\sum_{i=0}^ni\sum_{j=0}^{m-1}[\frac{cj+c-b-1}{a}<i] \\ 由于\ i 的取值是一个等差数列,首项为 \lfloor\frac{cj+c-b-1}{a}\rfloor+1 末项为 \ n \\ =\sum_{j=0}^{m-1}\frac{(n-\lfloor\frac{cj+c-b-1}{a}\rfloor)(n+\lfloor\frac{cj+c-b-1}{a}\rfloor+1)}{2} \\ =\frac{1}{2}\sum_{j=0}^{m-1}(n(n+1)-\lfloor\frac{cj+c-b-1}{a}\rfloor-\lfloor\frac{cj+c-b-1}{a}\rfloor^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(a\mod c,b\mod c,c,n)\\+\frac{n(n+1)(2n+1)}{6}\lfloor\frac{a}{c}\rfloor^2+(n+1)\lfloor\frac{b}{c}\rfloor^2\\+2\lfloor\frac{b}{c}\rfloor f(a\mod c,b\mod c,c,n)+2\lfloor\frac{a}{c}\rfloor g(a\mod c,b\mod c,c,n)+\lfloor\frac{b}{c}\rfloor\lfloor\frac{a}{c}\rfloor n(n+1)\)

    2. \(a<c\ and b<c\)

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

    \[\displaystyle h(a,b,c,n)=\sum_{i=0}^n(-\lfloor{\frac{ai+b}{c}}\rfloor+2\sum_{j=0}^{\lfloor{\frac{ai+b}{c}}\rfloor}j) \\ 将括号内部的两个式子分开计算 \\ =2\sum_{j=0}^{m-1}j+1\sum_{i=0}^n[\lfloor{\frac{ai+b}{c}}\rfloor\ge 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\n",ans.f,ans.h,ans.g);
        }
    }


}

int main()
{
    zzc::work();
    return 0;
}
posted @ 2021-01-18 20:36  youth518  阅读(73)  评论(0)    收藏  举报