类欧几里得学习笔记
- 类欧几里得可以等价于求 \(y=(ax+b)/c\) 这条直线和 \(x=0,y=0,x=n\) 围成的直角梯形内整点个数
前置芝士:
-

-
用途:快速求出以下式子的值
\(\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\)
-
\(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\)
-
\(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\)
-
\(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\)
-
\(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\)
-
\(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)\)
-
\(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;
}

浙公网安备 33010602011771号