[ARC123E] Training

发布时间 2023-11-15 10:04:33作者: SError

多测,求值

\[\sum_{i=1}^{n}\Big[a+\lfloor\frac{i}{b}\rfloor=c+\lfloor\frac{i}{d}\rfloor\Big] \]

\(1\le T\le 2\times 10^5\)\(1\le n\le 10^9\)\(1\le a,b,c,d\le 10^6\)


没见过,还得是广附哥。

\(b\le d\),设 \(f(x)=a+\dfrac{x}{b}\)\(g(x)=c+\dfrac{x}{d}\)\(F(x)=\lfloor f(x)\rfloor\)\(G(x)=\lfloor g(x)\rfloor\)

把下取整拆成不等式:\(\alpha-1<\lfloor\alpha\rfloor\le \alpha\),考虑函数 \(f(x)-g(x)\) 可能贡献的取值:

  • \(f(x)-g(x)\in(-1,0]\)\(F(x)-G(x)\in\{-1,0\}\)

  • \(f(x)-g(x)\in(0,1]\)\(F(x)-G(x)\in\{0,1\}\)

这两个区间可以二分得到。接下来考虑第一种情况,第二种同理。

\(\displaystyle \sum_{x=l}^{r}\Big[F(x)-G(x)=0\Big]\),由于 \(F(x)-G(x)\in\{-1,0\}\),对 \(F(x)-G(x)\) 求和,结果记为 \(k\),容易得到原式的值即 \(r-l+1+k\)

求和可以做到 \(O(1)\)太闲了可以草个类欧上去

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int read(){
	int x=0,w=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*w;
}
ll f(ll a,ll b,ll c,ll n){
	if(n<0)return 0;
	if(!a||!n)return (n+1)*(b/c);
	ll A=a/c,B=b/c;
	if(A||B)return n*(n+1)/2*A+B*(n+1)+f(a%c,b%c,c,n);
	ll M=(a*n+b)/c;
	return M*n-f(c,c-b-1,a,M-1);
}
ll calc(ll a,ll b,ll c,ll l,ll r){
	return f(a,b,c,r)-f(a,b,c,l-1);
}
ll n,a,b,c,d;
void solve(){
	n=read(),a=read(),b=read(),c=read(),d=read();
	if(b>d)swap(a,c),swap(b,d);
	ll l=1,r=n,mid;
	ll p1=-1,p2=n+1,p3=-1;
	while(l<=r){
		mid=(l+r)>>1;
		if(mid*(d-b)>b*d*(c-a-1))r=mid-1,p1=mid;
		else l=mid+1;
	}
	if(p1==-1)return puts("0"),void();
	l=p1,r=n;
	while(l<=r){
		mid=(l+r)>>1;
		if(mid*(d-b)>b*d*(c-a))r=mid-1,p2=mid;
		else l=mid+1;
	}
	l=p2,r=n;
	while(l<=r){
		mid=(l+r)>>1;
		if(mid*(d-b)<=b*d*(c-a+1))l=mid+1,p3=mid;
		else r=mid-1;
	}
	if(p3==-1)p3=p2-1;
	ll ans=0,k=calc(1,c*d,d,p1,p2-1)-calc(1,a*b,b,p1,p2-1);
	ans+=p2-p1-k;
	k=calc(1,a*b,b,p2,p3)-calc(1,c*d,d,p2,p3);
	ans+=p3-p2+1-k;
	printf("%lld\n",ans);
}
int main(){
	int T=read();
	while(T--)solve();
	
	return 0;
}