鲜花

从树论赶来的,感觉这个东西没什么用啊…QwQ

欧几里得

欧几里得算法

也称辗转相除法。

就是一个简单的式子:

gcd(a,b)=gcd(b,amodb)\gcd(a,b)=\gcd(b,a \bmod b)

证明如下:

令 b=ka+r , gcd(a,b)=d则有 d  a , d  br=bkabdkad=rd由于左边显然为整数r 和 a 的公约数相等r 和 a 的最大公约数相等\text{令 } b=ka+r\ ,\ gcd(a,b)=d\\ \text{则有 } d\ \vert\ a\ ,\ d\ \vert\ b\\ r=b-ka\Rightarrow \frac{b}{d} - \frac{ka}{d}=\frac{r}{d}\\ \text{由于左边显然为整数}\\ \therefore r\ \text{和 } a \text{ 的公约数相等}\\ \therefore r\ \text{和 } a \text{ 的最大公约数相等}

证毕。

扩展欧几里得算法(exgcd)

裴蜀定理

定理

对于任意不全为 00 的整数 a,ba,b,均存在一组整数 x,yx,y,使得 ax+by=gcd(a,b)ax+by=\gcd(a,b)

证明

d=gcd(a,b),a=a1d,b=b1dd=\gcd(a,b),a=a_1d,b=b_1d

则有 a1dx+b1dy=d(a1x+b1y)a_1dx+b_1dy=d(a_1x+b_1y)

那么可以把证明转化为对于任意不全为 00 的整数 a,ba,b 满足 gcd(a,b)=1\gcd(a,b)=1,存在一组整数 x,yx,y,满足 ax+by=1ax+by=1

考虑模拟一遍欧几里得算法求 gcd(a,b)\gcd(a,b)

gcd(a,b)gcd(b,amodb)gcd(amodb,bmod(amodb))\gcd(a,b)\Rightarrow\gcd(b,a\bmod b)\Rightarrow\gcd(a\bmod b,b\bmod(a\bmod b))\Rightarrow\cdots\cdots

发现很复杂,则把每一次的数记为 r1,r2,r3r_1,r_2,r_3,并记录每一次的等式:

rm1=rmqmrm2=rm1qm1+rmr1=r2q2+r3a=r1q1+r2r_{m-1}=r_mq_m\\ r_{m-2}=r_{m-1}q_{m-1}+r_m\\\cdots\cdots\\ r_1=r_2q_2+r_3\\ a=r_1q_1+r_2

考虑带入 gcd(a,b)=1\gcd(a,b)=1,则 rm=1r_m=1。然后把 qkq_k 换成 xk+1x_{k+1}

rm2=rm1xm+11=rm2xmrm1\cdots\Rightarrow r_{m-2}=r_{m-1}x_{m}+1\Rightarrow 1=r_{m-2}-x_mr_{m-1}

继续带入。

rm3=rm2xm1+rm1rm1=rm3rm2xm11=rm2xm(rm3xm1rm2)1=rm2xmrm3+xmxm1rm21=(1+xmxm1)rm2xmrm3rm4=rm3xm2+rm2rm2=rm4rm3xm21=(1+xmxm1)(rm4rm3xm2)xmrm31=(1+xmxm1)rm4(xm2xm1xm+xm2+xm)rm3r_{m-3}=r_{m-2}x_{m-1}+r_{m-1}\Rightarrow r_{m-1}=r_{m-3}-r_{m-2}x_{m-1}\\ \cdots\Rightarrow 1=r_{m-2}-x_m(r_{m-3}-x_{m-1}r_{m-2})\Rightarrow 1=r_{m-2}-x_mr_{m-3}+x_mx_{m-1}r_{m-2}\Rightarrow 1=(1+x_mx_{m-1})r_{m-2}-x_mr_{m-3}\\ r_{m-4}=r_{m-3}x_{m-2}+r_{m-2}\Rightarrow r_{m-2}=r_{m-4}-r_{m-3}x_{m-2}\\ \cdots\Rightarrow1=(1+x_mx_{m-1})(r_{m-4}-r_{m-3}x_{m-2})-x_mr_{m-3}\Rightarrow 1=(1+x_mx_{m-1})r_{m-4}-(x_{m-2}x_{m-1}x_m+x_{m-2}+x_m)r_{m-3}

可以通过模拟发现,总有系数可以满足等式左边为 11,由于最后 rr 可变为 a,ba,b,所以可推出 ax+by=1ax+by=1 成立。

证毕。

例题:P4549

显然 a1x+b1y=1a_1x+b_1y=1 是右边最小的情况。所以 ax+by=gcd(a,b)ax+by=\gcd(a,b) 是当前式子右边最小的情况。

由于 gcd(a,b)=gcd(a,b)\gcd(a,b)=\gcd(a,-b),所以只需要算出所有数的 gcd\gcd 即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include<bits/stdc++.h>
using namespace std;
int gcd(int a,int b){
if(a==0)return b;
return gcd(b%a,a);
}
int a[100001];
int main()
{
ios::sync_with_stdio(false);
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
a[i]=abs(a[i]);
}
for(int i=2;i<=n;i++)a[i]=gcd(a[i],a[i-1]);
cout<<a[n];
return 0;
}

应用:CF510D

根据裴蜀定理可得,当 gcd(a,b)=1\gcd(a,b)=1 时,一定有一组解 x,yx,y,能满足 ax+by=1ax+by=1,此时就能满足题中所要求的 能跳到所有位置上

然而题中要求最小。

考虑 dp,列出 dp 方程式:

fgcd(x,y)=min(fgcd(x,y),fx+cy)f_{\gcd(x,y)}=\min(f_{\gcd(x,y)},f_x+c_y)

使用 unordered_map 记录之前的状态,对于每个点进行转移即可。

时间复杂度 O(玄学)O(玄学)

咳咳,我之前写树上莫队的时候什么也没说。

但是很神奇的是用 unordered_mapWA,所以有点离谱。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include<bits/stdc++.h>
using namespace std;
int gcd(int a,int b){
if(!b)return a;
return gcd(b,a%b);
}
int n,l[301],c[303];
map<int,int> mp;
int main()
{
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++)cin>>l[i];
for(int i=1;i<=n;i++)cin>>c[i];
for(int i=1;i<=n;i++){
for(pair<int,int> x:mp){
int _next=gcd(x.first,l[i]);
if(!mp[_next])mp[_next]=c[i]+x.second;
else mp[_next]=min(mp[_next],c[i]+x.second);
// cout<<i<<" "<<_next<<"\n";
}
if(!mp[l[i]])mp[l[i]]=c[i];
else mp[l[i]]=min(mp[l[i]],c[i]);
}
if(!mp[1])mp[1]=-1;
cout<<mp[1];
return 0;
}

进一步结论

对于不定方程 ax+by=nax+by=n,如果该方程有解,则称 nn 能被(系数) a,ba,b 表示。

C=ababC=ab-a-b,发现 C=(a1)(b1)1C=(a-1)(b-1)-1,而若 a,ba,b 互质,那么至少其中有一个为偶数,那么 CC 必为奇数。

那么则有结论,对于任意整数 nnnnCnC-n 中只有一个能被 a,ba,b 表示

注意此处的 x,yx,y 为自然数,即 00 可被表示,CC 不可被表示;负数不可被表示,大于 CC 的数可被表示。

证明分三步:

令原方程解为:

{x=x0+bty=y0at\begin{cases} x=x_0+bt \cr y=y_0-at \end{cases}

如果控制 tt 的大小,yy 能控制在 00a1a-1 的范围内。其实可以发现对于 [0,C][0,C] 的数, yy 不可能超过 a1a-1

第一步:证明当 n>Cn>C 时,nn 都能被表示。

考虑 ymax=a1y_{max}=a-1,可以得到以下式子:

ax=nby>ababbyababb(a1)=ax>1ax=n-by>ab-a-b-by\geq ab-a-b-b(a-1)=-a\Rightarrow x>-1

可见 xx 也是非负整数。

第二步:证明 n=Cn=C 时,nn 不能被表示。

考虑如果 n=Cn=C 时有解,即满足 ax+by=ababax+by=ab-a-b

则有 ab=a(x+1)+b(y+1)a(bx1)=b(y+1)ab=a(x+1)+b(y+1)\Rightarrow a(b-x-1)=b(y+1)

由于 a,ba,b 互质,那么可以满足 bx1=kb , y+1=kab-x-1=kb\ ,\ y+1=ka

由于 y[0,a1]y\in[0,a-1],所以 k=1k=1。此时 x=1x=-1,矛盾,故 CC 不能被表示。

此处的证明是作者口胡的,所以与 OI Wiki 上的解释不同。

第三步:证明当 nn 不能被表示时,CnC-n 能被表示。

由于 nn 不能被表示,而 y[0,a1]y\in[0,a-1],故 xx 为负数。

Cn=ababaxby=a(1x)+b(a1y)C-n=ab-a-b-ax-by=a(-1-x)+b(a-1-y)

显然 1x-1-xa1ya-1-y 是非负的。

证毕。

几何意义看不懂。

另一种解释

考虑模 bb 意义下的每个剩余系最小能表示的值。因为 gcd(a,b)=1\gcd(a,b)=1,所以 0,a,2a,,(b1)a0,a,2a,\cdots,(b-1)a 在模 bb 的时候意义各不相同。

那么小于等于 nn 的能表示的所有非负整数的数量为:

i=0nanaib\sum_{i=0}^{\left\lfloor \frac{n}{a} \right\rfloor}\left\lfloor\frac{n-ai}{b}\right\rfloor

因为对于所有剩余系的意义不同,所以要将所有剩余系的贡献累加。

用类欧几里得算法可以做到 O(log(max(a,b)))O(\log(\max(a,b)))

exgcd

这个东西主要是来求不定方程 ax+by=gcd(a,b)ax+by=\gcd(a,b) 的一组整数解。也就是构造裴蜀定理的一组解。

构造过程

考虑证明裴蜀定理的时候,对于 gcd(a,b)=1\gcd(a,b)=1 的情况,我们是直接对欧几里得算法进行了反带最后得出解。

有了计算机,那么我们可以反带 gcd(a,b)1\gcd(a,b)\ne 1 的情况,是与 gcd(a,b)=1\gcd(a,b)=1 时差不多的。

下面就是推式子环节了。

首先,对于欧几里得算法退出时,它的返回条件是 b=0b=0,可发现此时一组可行解为:(不换行太丑了)

{x=1y=0\begin{cases}x=1\cr y=0\end{cases}

然后对于任意 ax+by=gcd(a,b)ax+by=\gcd(a,b),考虑转化为递推。

ax+by=gcd(a,b)=gcd(b,amodb)=bx0+(amodb)y0ax+by=bx0+(aab×b)y0=ay0+b(x0aby0)ax+by=\gcd(a,b)=\gcd(b,a \bmod b)=bx_0+(a\bmod b)y_0\\ \Rightarrow ax+by=bx_0+(a-\left\lfloor\frac{a}{b}\right\rfloor\times b)y_0=ay_0+b(x_0-\left\lfloor\frac{a}{b}\right\rfloor y_0)

所以推出一组可行的解 x=y0 , y=x0aby0x=y_0\ ,\ y=x_0-\left\lfloor\frac{a}{b}\right\rfloor y_0

递推即可。

例题:P5656

这题要求是真的多。

首先用 exgcd 算出一组特解,然后来考虑各组解的关系。

列出式子 a(x+p)+b(yq)=ax+by=ca(x+p)+b(y-q)=ax+by=c,发现 ap=bqap=bq

由于 ppqq 均为整数,所以 pmin=1a×lcm(a,b)p_{min}=\frac{1}{a}\times\operatorname{lcm}(a,b)qminq_{min} 同。

然后就可以直接算出题中要求的所有信息了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include<bits/stdc++.h>
using namespace std;
#define int long long
int x,y,_a,_b,_c;
int exgcd(int a,int b){
int d=a;
if(b==0)x=1,y=0;
else d=exgcd(b,a%b),swap(x,y),y-=a/b*x;
return d;
}

signed main(){
ios::sync_with_stdio(0);
int n;
cin>>n;
while(n--){
cin>>_a>>_b>>_c;
int d=exgcd(_a,_b);
if(_c%d){
cout<<-1<<"\n";
continue;
}
int k=_c/d;
x*=k,y*=k;
int p=_b/d,q=_a/d;//a(x+p)+b(y-q)=c,要交叉对应,别写反了!!!!
//用x,y其中一个最小整数解对应的那个数判断
int test=y/q;
int tx=test*p+x,ty=-test*q+y;
if(ty<=0)ty+=q,tx-=p;
if(tx<=0){
cout<<-(tx/p)*p+p+tx<<" "<<ty<<"\n";
}
else{
cout<<(tx-1)/p+1<<" "<<(tx-1)%p+1<<" "<<ty<<" "<<tx<<" "<<(tx-1)/p*q+ty<<"\n";
}
}
return 0;
}

例题:P1516

考虑把这道题的参数转换成 ax+by=nax+by=n

考虑追及问题,所以可以列出:Δvx+Ly=Δs\Delta vx+Ly=\Delta s

算出特解之后像上面那道题一样算 xx 的最小正整数解即可。

注意 Δv\Delta v 必须为正,如果要取反记得把 Δs\Delta s 也要取反。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m,x,y,L;
int _x,_y;
int exgcd(int a,int b){
int d=a;
if(!b)_x=1,_y=0;
else d=exgcd(b,a%b),swap(_x,_y),_y-=a/b*_x;
return d;
}
signed main(){
ios::sync_with_stdio(0);
cin>>x>>y>>m>>n>>L;
int z=n-m,f=x-y;
if(z<0)z=-z,f=-f;
if(f==0){
cout<<0;
return 0;
}
// cout<<z<<" "<<L<<" "<<f<<"\n";
int k=exgcd(z,L),p=L/k,q=z/k;//!!!
// cout<<k<<"\n";
_x*=(f/k),_y*=(f/k);
// cout<<p<<" "<<q<<" "<<_x<<" "<<_y<<"\n";
if(f%k){
cout<<"Impossible";
}
else{
if(_x>0)cout<<(_x-1)%p+1;
else cout<<_x%p+p;
}
return 0;
}

例题:P1082

水题。

考虑式子 ax1(modb)ax \equiv 1\pmod b,可以转换成 axby=1ax-by=1,由于题中说保证有解,故直接求 xx 的最小正整数解即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include<bits/stdc++.h>
using namespace std;
int x,y;
int exgcd(int a,int b){
int d=a;
if(!b)x=1,y=0;
else d=exgcd(b,a%b),swap(x,y),y-=a/b*x;
return d;
}
int main(){
ios::sync_with_stdio(0);
int n,m;
cin>>n>>m;
int d=exgcd(n,m);
y=-y;
int p=m/d,ans;
if(x>0)ans=(x-1)%p+1;
else ans=x%p+p;
cout<<ans;
return 0;
}

例题:P2421

较复杂的一道题。

判断每个野人生存周期以内的两两的 exgcd 即可。

然后由于没有单调性不能二分,直接枚举就行了。

和 P1516 差不多。

时间复杂度 O(Mn2logc)O(Mn^2\log c),随机打乱野人的遍历顺序之后应该能做到更优。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include<bits/stdc++.h>
using namespace std;
int x,y;
int exgcd(int a,int b){
int d=a;
if(!b)x=1,y=0;
else d=exgcd(b,a%b),swap(x,y),y-=a/b*x;
return d;
}
int c[21],p[21],l[21],n;
bool check(int L){
for(int i=1;i<=n;i++){
for(int j=1;j<i;j++){
int z=p[j]-p[i],f=c[i]-c[j];
if(z<0)z=-z,f=-f;
if(f==0)return 0;
int d=exgcd(z,L);
if(f%d)continue;
int p=L/d,q=z/d;
x*=(f/d),y*=(f/d);
// cout<<x<<" "<<p<<" "<<i<<" "<<j<<" "<<f<<" "<<d<<"\n";
int ans;
if(x>0)ans=(x-1)%p+1;
else ans=x%p+p;
if(ans<=l[i]&&ans<=l[j])return 0;
}
}
return 1;
}
int maxc=-1;
int main(){
ios::sync_with_stdio(0);
cin>>n;
for(int i=1;i<=n;i++)cin>>c[i]>>p[i]>>l[i],maxc=max(c[i],maxc);
for(;;maxc++)if(check(maxc)){
cout<<maxc;
return 0;
}
return 0;
}

应用:UVA12775

枚举每个 CC,然后先求 exgcd(A,B)\operatorname{exgcd}(A,B),然后枚举每个 Ax+By=PiCAx+By=P-iC 的解的数量即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// Problem: Gift Dilemma
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/UVA12775
// Memory Limit: 0 MB
// Time Limit: 3000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
#define int long long
int T,a,b,c,p,x,y;
int exgcd(int a,int b){
int d=a;
if(!b)x=1,y=0;
else d=exgcd(b,a%b),swap(x,y),y-=a/b*x;
return d;
}
signed main(){
ios::sync_with_stdio(0);
cin>>T;
int Y=T;
while(T--){
int ans=0;
cin>>a>>b>>c>>p;
int d=exgcd(a,b);
for(int i=0;i*c<=p;i++){
if((p-i*c)%d)continue;
int tx=x*(p-i*c)/d,ty=y*(p-i*c)/d;
int p=b/d,q=a/d;
// cout<<tx<<" "<<ty<<" "<<p<<" "<<q<<"\n";
int res=0;
if(tx>=0||tx%p==0)res=tx%p;
else res=tx%p+p;
res=(res-tx)/p;
ty-=res*q;
if(ty>=0)ans+=ty/q+1;
// cout<<ty-res*q<<" "<<res<<"\n";
}
cout<<"Case "<<Y-T<<": "<<ans<<"\n";
}
return 0;
}

应用:UVA10104

不会证明这个结论,因此直接搬 tj 了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Problem: Euclid Problem
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/UVA10104
// Memory Limit: 0 MB
// Time Limit: 3000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
int x,y;
int exgcd(int a,int b){
int d=a;
if(!b)x=1,y=0;
else d=exgcd(b,a%b),swap(x,y),y-=a/b*x;
return d;
}
int main(){
ios::sync_with_stdio(0);
int a,b,gcd;
while(cin>>a>>b)gcd=exgcd(a,b),cout<<x<<" "<<y<<" "<<gcd<<"\n";
return 0;
}

类欧几里得算法

这个算法是用来在 O(logn)O(\log n) 的时间内计算下面三个函数:

f(a,b,c,n)=i=0nai+bcg(a,b,c,n)=i=0niai+bch(a,b,c,n)=i=0nai+bc2f(a,b,c,n)=\sum_{i=0}^n\left\lfloor\frac{ai+b}{c}\right\rfloor\\ g(a,b,c,n)=\sum_{i=0}^ni\left\lfloor\frac{ai+b}{c}\right\rfloor\\ h(a,b,c,n)=\sum_{i=0}^n\left\lfloor\frac{ai+b}{c}\right\rfloor^2

推式子

然后开始艰难地推式子…

先令 s0(n)=n+1 , s1(n)=(n+1)n2 , s2(n)=n(n+1)(2n+1)6s^0(n)=n+1\ ,\ s^1(n)=\frac{(n+1)n}{2}\ ,\ s^2(n)=\frac{n(n+1)(2n+1)}{6}

对于 a>c \or b>c 的情况:

f(a,b,c,n)=i=0nai+bc=i=0n((amodc)i+bmodcc+aci+bc)=bc×s0(n)+ac×s1(n)+f(amodc,bmodc,c,n)g(a,b,c,n)=i=0niai+bc=i=0ni((amodc)i+bmodcc+aci+bc)=i=0n(aci2+bci)+g(amodc,bmodc,c,n)=ac×s2(n)+bc×s1(n)+g(amodc,bmodc,c,n)h(a,b,c,n)=i=0nai+bc2=i=0n((amodc)i+bmodcc+aci+bc)2=h(amodc,bmodc,c,n)+2acg(amodc,bmodc,c,n)+2bcf(amodc,bmodc,c,n)+i=0n(ac2i2+bc2+2acbci)=s0(n)×bc2+s1(n)×2acbc+s2(n)×ac2+h(amodc,bmodc,c,n)+2acg(amodc,bmodc,c,n)+2bcf(amodc,bmodc,c,n)\begin{aligned} f(a,b,c,n)&=\sum_{i=0}^n\left\lfloor\frac{ai+b}{c}\right\rfloor\cr &=\sum_{i=0}^n\left(\left\lfloor\frac{(a\bmod c)i+b\bmod c}{c}\right\rfloor+\left\lfloor\frac{a}{c}\right\rfloor i+\left\lfloor\frac{b}{c}\right\rfloor\right)\cr &=\left\lfloor\frac{b}{c}\right\rfloor\times s^0(n)+\left\lfloor\frac{a}{c}\right\rfloor \times s^1(n)+f(a\bmod c,b\bmod c,c,n)\cr g(a,b,c,n)&=\sum_{i=0}^ni\left\lfloor\frac{ai+b}{c}\right\rfloor\cr &=\sum_{i=0}^ni\left(\left\lfloor\frac{(a\bmod c)i+b\bmod c}{c}\right\rfloor+\left\lfloor\frac{a}{c}\right\rfloor i+\left\lfloor\frac{b}{c}\right\rfloor\right)\cr &=\sum_{i=0}^n\left(\left\lfloor\frac{a}{c}\right\rfloor i^2+\left\lfloor\frac{b}{c}\right\rfloor i\right)+g(a\bmod c,b\bmod c,c,n)\cr &=\left\lfloor\frac{a}{c}\right\rfloor\times s^2(n)+\left\lfloor\frac{b}{c}\right\rfloor\times s^1(n)+g(a\bmod c,b\bmod c,c,n)\cr h(a,b,c,n)&=\sum_{i=0}^n\left\lfloor\frac{ai+b}{c}\right\rfloor^2\cr &=\sum_{i=0}^n\left(\left\lfloor\frac{(a\bmod c)i+b\bmod c}{c}\right\rfloor+\left\lfloor\frac{a}{c}\right\rfloor i+\left\lfloor\frac{b}{c}\right\rfloor\right)^2\cr &=h(a\bmod c,b\bmod c,c,n)+2\left\lfloor\frac{a}{c}\right\rfloor g(a\bmod c,b\bmod c,c,n)+2\left\lfloor\frac{b}{c}\right\rfloor f(a\bmod c,b\bmod c,c,n)+\sum_{i=0}^n\left(\left\lfloor\frac{a}{c}\right\rfloor^2 i^2+\left\lfloor\frac{b}{c}\right\rfloor^2+2\left\lfloor\frac{a}{c}\right\rfloor \left\lfloor\frac{b}{c}\right\rfloor i\right)\cr &=s^0(n)\times \left\lfloor\frac{b}{c}\right\rfloor^2+s^1(n)\times 2\left\lfloor\frac{a}{c}\right\rfloor\left\lfloor\frac{b}{c}\right\rfloor+s^2(n)\times \left\lfloor\frac{a}{c}\right\rfloor^2+h(a\bmod c,b\bmod c,c,n)+2\left\lfloor\frac{a}{c}\right\rfloor g(a\bmod c,b\bmod c,c,n)+2\left\lfloor\frac{b}{c}\right\rfloor f(a\bmod c,b\bmod c,c,n) \end{aligned}

作者的手已经打废了。/kk

对于 a<c\and b<c 的情况:

先看三个式子同样要用到的东西:

m=an+bc\displaystyle m=\left\lfloor\frac{an+b}{c}\right\rfloor

i=0n[j<ai+bc]=i=0n[j+1ai+bc]=i=0n[jc+cai+b]=i=0n[aijc+cb]=i=0n[ai>jc+cb1]=i=0n[i>jc+c+b1a]=njc+c+b1a\begin{aligned} \sum_{i=0}^n\left[j<\left\lfloor\frac{ai+b}{c}\right\rfloor\right]&=\sum_{i=0}^n\left[j+1\leq\frac{ai+b}{c}\right]\cr &=\sum_{i=0}^{n}\left[jc+c\leq ai+b\right]\cr &=\sum_{i=0}^{n}[ai\geq jc+c-b]\cr &=\sum_{i=0}^n[ai>jc+c-b-1]\cr &=\sum_{i=0}^n\left[i>\left\lfloor\frac{jc+c+b-1}{a}\right\rfloor\right]\cr &=n-\left\lfloor\frac{jc+c+b-1}{a}\right\rfloor \end{aligned}

然后逐个击破:

f(a,b,c,n)=i=0nai+bc=i=0nj=0ai+bc11=i=0nj=0m1[j<ai+bc]=j=0m1i=0n[j<ai+bc]=j=0m1(njc+c+b1a)=nmf(c,cb1,a,m1)g(a,b,c,n)=i=0niai+bc=i=0nj=0ai+bc1i=i=0nj=0m1([j<ai+bc]×i)=j=0m1i=0n([j<ai+bc]×i)=j=0m1i=0n([i>jc+c+b1a]×i)=j=0m1(n+jc+c+b1a+1)×(njc+c+b1a)2=j=0m1(n2jc+c+b1a2+njc+c+b1a)2=n(n+1)mh(c,cb1,a,m1)f(c,cb1,a,m1)2h(a,b,c,n)=i=0nai+bc2=2i=0nj=0ai+bc1(j+1)i=0nai+bc=2i=0nj=0m1([j<ai+bc]×(j+1))f(a,b,c,n)=2j=0m1(j+1)i=0n[j<ai+bc]f(a,b,c,n)=2j=0m1((j+1)×(njc+c+b1a))f(a,b,c,n)=(m+1)mn2j=0m1(jjc+c+b1a+jc+c+b1a)f(a,b,c,n)=(m+1)mn2g(c,cb1,a,m1)2f(c,cb1,a,m1)f(a,b,c,n)\begin{aligned} f(a,b,c,n)&=\sum_{i=0}^n\left\lfloor\frac{ai+b}{c}\right\rfloor\cr &=\sum_{i=0}^n\sum_{j=0}^{\lfloor\frac{ai+b}{c}\rfloor-1}1\cr &=\sum_{i=0}^n\sum_{j=0}^{m-1}\left[j<\left\lfloor\frac{ai+b}{c}\right\rfloor\right]\cr &=\sum_{j=0}^{m-1}\sum_{i=0}^n\left[j<\left\lfloor\frac{ai+b}{c}\right\rfloor\right]\cr &=\sum_{j=0}^{m-1}\left(n-\left\lfloor\frac{jc+c+b-1}{a}\right\rfloor\right)\cr &=nm-f(c,c-b-1,a,m-1)\cr g(a,b,c,n)&=\sum_{i=0}^ni\left\lfloor\frac{ai+b}{c}\right\rfloor\cr &=\sum_{i=0}^n\sum_{j=0}^{\lfloor\frac{ai+b}{c}\rfloor-1}i\cr &=\sum_{i=0}^n\sum_{j=0}^{m-1}\left(\left[j<\left\lfloor\frac{ai+b}{c}\right\rfloor\right]\times i\right)\cr &=\sum_{j=0}^{m-1}\sum_{i=0}^n\left(\left[j<\left\lfloor\frac{ai+b}{c}\right\rfloor\right]\times i\right)\cr &=\sum_{j=0}^{m-1}\sum_{i=0}^n\left(\left[i>\left\lfloor\frac{jc+c+b-1}{a}\right\rfloor\right]\times i\right)\cr &=\sum_{j=0}^{m-1}\frac{\left(n+\left\lfloor\frac{jc+c+b-1}{a}\right\rfloor+1\right)\times\left(n-\left\lfloor\frac{jc+c+b-1}{a}\right\rfloor\right)}{2}\cr &=\frac{\displaystyle\sum_{j=0}^{m-1}\left(n^2-\left\lfloor\frac{jc+c+b-1}{a}\right\rfloor^2+n-\left\lfloor\frac{jc+c+b-1}{a}\right\rfloor\right)}{2}\cr &=\frac{n(n+1)m-h(c,c-b-1,a,m-1)-f(c,c-b-1,a,m-1)}{2}\cr h(a,b,c,n)&=\sum_{i=0}^n\left\lfloor\frac{ai+b}{c}\right\rfloor^2\cr &=2\sum_{i=0}^n\sum_{j=0}^{\lfloor\frac{ai+b}{c}\rfloor-1}(j+1)-\sum_{i=0}^n\left\lfloor\frac{ai+b}{c}\right\rfloor\cr &=2\sum_{i=0}^n\sum_{j=0}^{m-1}\left(\left[j<\left\lfloor\frac{ai+b}{c}\right\rfloor\right]\times (j+1)\right)-f(a,b,c,n)\cr &=2\sum_{j=0}^{m-1}(j+1)\sum_{i=0}^n\left[j<\left\lfloor\frac{ai+b}{c}\right\rfloor\right]-f(a,b,c,n)\cr &=2\sum_{j=0}^{m-1}\left((j+1)\times \left(n-\left\lfloor\frac{jc+c+b-1}{a}\right\rfloor\right)\right)-f(a,b,c,n)\cr &=(m+1)mn-2\sum_{j=0}^{m-1}\left(j\left\lfloor\frac{jc+c+b-1}{a}\right\rfloor+\left\lfloor\frac{jc+c+b-1}{a}\right\rfloor\right)-f(a,b,c,n)\cr &=(m+1)mn-2g(c,c-b-1,a,m-1)-2f(c,c-b-1,a,m-1)-f(a,b,c,n) \end{aligned}

边界:

f(0,b,c,n)=s0(n)×bcg(0,b,c,n)=s1(n)×bch(0,b,c,n)=s0(n)×bc2\begin{aligned} f(0,b,c,n)&=s^0(n)\times \left\lfloor\frac{b}{c}\right\rfloor\cr g(0,b,c,n)&=s^1(n)\times \left\lfloor\frac{b}{c}\right\rfloor\cr h(0,b,c,n)&=s^0(n)\times\left\lfloor\frac{b}{c}\right\rfloor^2\cr \end{aligned}

写完这个东西就去复习 CSP 了。

板子题:P5170

没啥可说的,注意取模即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include<bits/stdc++.h>
using namespace std;
#define int long long
const long long mod=998244353;
struct R{
int f,g,h;
}ans;
R getr(int _f,int _g,int _h){
R temp;
temp.f=_f;
temp.g=_g;
temp.h=_h;
return temp;
}
int I2=499122177,I6=166374059;
int s0(int k){
return k+1;
}
int s1(int k){
return k*(k+1)%mod*I2%mod;
}
int s2(int k){
return k*(k+1)%mod*(2*k+1)%mod*I6%mod;
}
R simgcd(int a,int b,int c,int n){
int F=0,G=0,H=0;
if(a==0)return getr((b/c)*s0(n)%mod,(b/c)*s1(n)%mod,(b/c)*(b/c)%mod*s0(n)%mod);
R res;
if(a>=c||b>=c){
res=simgcd(a%c,b%c,c,n);
F=res.f+b/c*s0(n)%mod+a/c*s1(n)%mod;
G=res.g+a/c*s2(n)%mod+b/c*s1(n)%mod;
H=b/c*2*res.f%mod+a/c*2*res.g%mod+res.h+b/c*(b/c)%mod*s0(n)%mod+b/c*(a/c)*2%mod*s1(n)%mod+(a/c)*(a/c)%mod*s2(n)%mod;
return getr(F%mod,G%mod,H%mod);
}
int m=(a*n+b)/c;
res=simgcd(c,c-b-1,a,m-1);
F=n*m%mod-res.f%mod;
G=(n*(n+1)%mod*m%mod-res.h%mod-res.f%mod)*I2%mod;
H=(m+1)*m%mod*n%mod+-2*res.g%mod-2*res.f%mod-F%mod;
return getr((F%mod+mod)%mod,(G%mod+mod)%mod,(H%mod+mod)%mod);
}

signed main(){
ios::sync_with_stdio(0);
int T,aa,bb,cc,nn;
cin>>T;
while(T--){
cin>>nn>>aa>>bb>>cc;
ans=simgcd(aa,bb,cc,nn);
cout<<(ans.f%mod)<<" "<<(ans.h%mod)<<" "<<(ans.g%mod)<<"\n";
}
return 0;
}

应用:P5171

CSP 复习前的最后一道题。

考虑分开讨论 x,yx,y

之前好像有证明 gcd(a,b)=1\gcd(a,b)=1 的特殊情况的式子。

先讨论 yy 的范围:

ax+bycbycaxycaxbax+by\leq c\Rightarrow by\leq c-ax\Rightarrow y\leq\left\lfloor\frac{c-ax}{b}\right\rfloor

所以对于 yy ,合法的 xx 至多有 caxb+1\left\lfloor\frac{c-ax}{b}\right\rfloor+1 个。

再来讨论 xx 的范围。考虑当 y=0y=0 的极限情况,xx 最大就是 ca\lfloor\frac{c}{a}\rfloor,所以 x[0,ca]x\in[0,\left\lfloor\frac{c}{a}\right\rfloor]

所以式子列出来就是:

x=0ca(caxb+1)\sum_{x=0}^{\left\lfloor\frac{c}{a}\right\rfloor}\left(\left\lfloor\frac{c-ax}{b}\right\rfloor+1\right)

因为 a<0-a<0,要进行转化。考虑此时的 xxyy 无论以哪个作为对象都能得到答案,所以此时的 a,ba,b 互换是没有影响的,所以可以将式子改写为:

x=0ca((ba)x+cbx)+s0(ca)=x=0ca(ba)x+cbs1(ca)+s0(ca)\sum_{x=0}^{\left\lfloor\frac{c}{a}\right\rfloor}\left(\left\lfloor\frac{(b-a)x+c}{b}\right\rfloor-x\right)+s^0\left(\left\lfloor\frac{c}{a}\right\rfloor\right)=\sum_{x=0}^{\left\lfloor\frac{c}{a}\right\rfloor}\left\lfloor\frac{(b-a)x+c}{b}\right\rfloor-s^1\left(\left\lfloor\frac{c}{a}\right\rfloor\right)+s^0\left(\left\lfloor\frac{c}{a}\right\rfloor\right)

然后就可以求解了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// Problem: P5171 Earthquake
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P5171
// Memory Limit: 125 MB
// Time Limit: 250 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
#define int long long
int s0(int k){
return k+1;
}
int s1(int k){
return k*(k+1)/2;
}
int simgcd(int a,int b,int c,int n){
int res=0;
if(a>=c||b>=c)res+=s1(n)*(a/c)+s0(n)*(b/c),a%=c,b%=c;
if(a==0)return s0(n)*(b/c)+res;
int m=(a*n+b)/c;
return m*n-simgcd(c,c-b-1,a,m-1)+res;
}
signed main(){
ios::sync_with_stdio(0);
int A,B,C;
cin>>A>>B>>C;
if(A>B)swap(A,B);
int ans=simgcd(B-A,C,B,C/A);
ans-=s1(C/A)-C/A;
cout<<ans+1;
return 0;
}

这里应该还有 33 道类欧没有写,CSP 回来之后再写,祝 RP++!

没写的:AT_abc283_h,P5172,P5179。