[atARC111E]Simple Math 3
首先,必然要有$(a+ci)-(a+bi)+1<d$,因此$(c-b)i\le d-2$,即$i\le \lfloor\frac{d-2}{c-b}\rfloor$
此时,$[a+bi,a+ci]$中不存在$d$的倍数,当且仅当$\lfloor\frac{a+bi-1}{d}\rfloor=\lfloor\frac{c+bi}{d}\rfloor$,同时两者之差不大于2,因此可以通过求和来统计,即$n-\sum_{i=1}^{n}\lfloor\frac{a+ci}{d}\rfloor-\lfloor\frac{a+bi-1}{d}\rfloor$(其中$n=\lfloor\frac{d-2}{c-b}\rfloor$)
这两个式子是类似的,因此可以仅考虑$\sum_{i=1}^{n}\lfloor\frac{a+ci}{d}\rfloor$
将后者用1累加的形式来表示,即$\sum_{i=1}^{n}\sum_{1\le j\le \lfloor\frac{a+ci}{d}\rfloor}1$
调换枚举顺序,令$n'=\lfloor\frac{a+cn}{d}\rfloor$,因此即$\sum_{j=1}^{n'}\sum_{1\le i\le n,j\le \lfloor\frac{a+ci}{d}\rfloor}1$
考虑$j\le \lfloor\frac{a+ci}{d}\rfloor$,改为用$j$来限制$i$,即$\lceil\frac{jd-a}{c}\rceil=\lfloor\frac{jd-a+c-1}{c}\rfloor\le i\le n$
同时注意到$a<d$且$j\ge 1$,即保证了$\lfloor\frac{jd-a+c-1}{c}\rfloor\ge 1$
再将后者1的累加展开,即$\sum_{j=1}^{n'}n-\lfloor\frac{jd-a+c-1}{c}\rfloor+1=n'(n+1)-\sum_{j=1}^{n'}\lfloor\frac{(c-a-1)+jd}{c}\rfloor$
因此,即记$f(n,a,c,d)=\sum_{i=1}^{n}\max(\lfloor\frac{a+ci}{d}\rfloor,0)$,则$f(n,a,c,d)=n'(n+1)-f(n',c-a-1,d,c)$
另外,$f(n,a,c,d)$还有以下变换来规范其形式,即:
1.若$a\ge d$,$f(n,a,c,d)=f(n,a\ mod\ d,c,d)+\lfloor\frac{a}{d}\rfloor n$
2.若$a<0$,$f(n,a,c,d)=f(n,a+kd,c,d)-kn$(其中$k=\lfloor\frac{-a+d-1}{d}\rfloor$)
3.若$c\ge d$,$f(n,a,c,d)=f(n,a,c\ mod\ d,d)+\lfloor\frac{c}{d}\rfloor{n+1\choose 2}$
4.若$c=0$,$f(n,a,c,d)=0$
注意到其关于$(c,d)$的变换形式与扩展欧几里得相同,因此复杂度为$o(\log_{2}d)$
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 int t,a,b,c,d; 5 ll n;#include<bits/stdc++.h> 6 using namespace std; 7 #define ll long long 8 int t,a,b,c,d; 9 ll n; 10 ll f(ll n,int a,int c,int d){ 11 if (a>=d)return f(n,a%d,c,d)+(a/d)*n; 12 if (a<0){ 13 int k=(-a+d-1)/d; 14 return f(n,a+k*d,c,d)-k*n; 15 } 16 if (c>=d)return f(n,a,c%d,d)+(n+1)*n/2*(c/d); 17 if (!c)return 0; 18 ll nn=(a+c*n)/d; 19 return nn*(n+1)-f(nn,c-a-1,d,c); 20 } 21 int main(){ 22 scanf("%d",&t); 23 while (t--){ 24 scanf("%d%d%d%d",&a,&b,&c,&d); 25 n=(d-2)/(c-b); 26 printf("%lld\n",n-f(n,a,c,d)+f(n,a-1,b,d)); 27 } 28 } 29 ll f(ll n,int a,int c,int d){ 30 if (a>=d)return f(n,a%d,c,d)+(a/d)*n; 31 if (a<0){ 32 int k=(-a+d-1)/d; 33 return f(n,a+k*d,c,d)-k*n; 34 } 35 if (c>=d)return f(n,a,c%d,d)+(n+1)*n/2*(c/d); 36 if (!c)return 0; 37 ll nn=(a+c*n)/d; 38 return nn*(n+1)-f(nn,c-a-1,d,c); 39 } 40 int main(){ 41 scanf("%d",&t); 42 while (t--){ 43 scanf("%d%d%d%d",&a,&b,&c,&d); 44 n=(d-2)/(c-b); 45 printf("%lld\n",n-f(n,a,c,d)+f(n,a-1,b,d)); 46 } 47 }