题意:给出x1,x2,y1,y2,求:![](https://i-blog.csdnimg.cn/blog_migrate/9c294488baa6dec074c98781357f5d70.png)
范围:![](https://i-blog.csdnimg.cn/blog_migrate/fe947352b0ba76aa19d1c98e3ca58965.png)
![](https://i-blog.csdnimg.cn/blog_migrate/d4e4cbf618529e7bbc0ee28eb0d97096.png)
思路:
令A=
,B=
,C=
,D=
.
(A+B+C+D)^2=(A+B)^2+(C+D)^2+2*(A+B)*(C+D)=A^2+B^2+C^2+D^2+2* (AB+AC+AD+BC+BD+CD);
A^2与C^2
是同一个类型,所以我们以A^2以例来推理(只看外围循坏,因为内围循环j从y1到y2,A是不变的,最后只要乘上y2-y1+1即可)
假设x1=4,x2=17,i从x1到x2,A^2分别是1,1,1,1,4,4,4,4,9,9,9,9,16,16
可以推出:令n=x2/x1-1, 则i从x1到x2,A^2 = x1 * ( 1^2 + 2^2 + 3^2 + ... + n^2 ) + ( x2 + 1 - ( n + 1 ) * x1 ) * ( n + 1 )* ( n + 1 )
又1^2 + 2^2 + 3^2 + ... + n^2 = n * ( n + 1 ) * ( 2 * n + 1 ) / 6;
A^2 = x1 * n * ( n + 1 ) * ( 2 * n + 1 ) / 6 + ( x2 + 1 - ( n + 1 ) * x1 ) * ( n + 1 ) ;
A^2的答案ans= x1 * n * ( n + 1 ) * ( 2 * n + 1 ) / 6 + ( x2 + 1 - ( n + 1 ) * x1 ) * ( n + 1 )* ( n + 1 ),
最后ans = ans * ( y2 - y1 + 1 ) ;
B^2与D^2
经典整除分块算法
(配上整除分块模板)
我们只需要将ans+=(r-l+1)*(n/l)改为ans+=(r-l+1)*(n/l)*(n/l),
最后再乘以(y2-y1+1)就行了
AB 与 CD
以AB来说用到的还是整除分块算法,只不过在每求的一个l,r求出A的[l,r]的和;
求A的[l,r]的和我们可以参照求A^2来求A的前缀和sum,然后sum[r]-sum[l-1]即位所求
最后还是要乘以(y2-y1+1),还有别忘了乘2,因为是2*AB
AC
A与C是互不影响的,所以AC等于A的总和乘以C的总和
ansA=x1 * n * ( n + 1 ) / 2 + ( x2 + 1 - ( n + 1 ) * x1 ) * ( n + 1 ) , 其中 n=x2/x1-1,
n*(n+1)/2=1+2+3+...+n
ansC=y1 * n * ( n + 1 ) / 2 + ( y2 + 1 - ( n + 1 ) * y1 ) * ( n + 1 ), 其中 n=y2/y1-1,
n*(n+1)/2=1+2+3+...+n
ans=ansA*ansC*2;
AD,BC,BD
同样这三个也是互不影响的,与AC推理相似,不过B与D要用到整除分块算法,这里就不再一一推理了
最后需要注意,整数分块的时间复杂度为O(√ ̄n),n为1e9,这一题是多样例,t<=100,然后/6与/2要求6与2的逆元为O(log2(1e9))
总体,3e4*100*30大概为1e8且有的常数还没有算,因此会超时,所以我们可以预处理6的逆元与2的逆元
代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
const int mod=1e9+7;
const LL ni6=166666668,ni2=500000004;
LL x1,x2,y1,y2;
LL ans;
//LL qmi(LL a,LL k)
//{
// LL res=1;
// while(k)
// {
// if(k&1) res=res*a%mod;
// a=a*a%mod;
// k>>=1;
// }
// return res;
//}
LL A2(LL x1,LL x2,LL y1,LL y2)
{
LL n=x2/x1-1;
LL a=x1*n%mod*(n+1)%mod*(2*n+1)%mod*ni6%mod;
LL b=(x2+1-(n+1)*x1)*(n+1)%mod*(n+1)%mod;
return (a+b)%mod*(y2-y1+1)%mod;
}
LL B2(LL x1,LL x2,LL y1,LL y2)
{
LL res=0;
for(LL l=x1,r;l<=x2;l=r+1)
{
r=x2/(x2/l);
res=(res+(r-l+1)*(x2/l)%mod*(x2/l)%mod)%mod;
}
res=res*(y2-y1+1)%mod;
return res;
}
LL sum(LL x1,LL x)
{
LL n=x/x1-1;
LL res=x1*n%mod*(n+1)%mod*ni2%mod;
res=(res+(x+1-x1-n*x1)*(n+1)%mod)%mod;
return res;
}
LL AB(LL x1,LL x2,LL y1,LL y2)
{
LL res=0;
for(LL l=x1,r;l<=x2;l=r+1)
{
r=x2/(x2/l);
LL cnt=(sum(x1,r)-sum(x1,l-1)+mod)%mod;
res=(res+cnt*(x2/l)%mod)%mod;
}
return res*(y2-y1+1)%mod*2%mod;
}
LL A(LL x1,LL x2)
{
LL n=x2/x1-1;
LL a=x1*n%mod*(n+1)%mod*ni2%mod;
LL b=(x2+1-x1-n*x1)*(n+1)%mod;
return (a+b)%mod;
}
LL B(LL x1,LL x2)
{
LL res=0;
for(LL l=x1,r;l<=x2;l=r+1)
{
r=x2/(x2/l);
res=(res+(r-l+1)*(x2/l)%mod)%mod;
}
return res;
}
LL AC(LL x1,LL x2,LL y1,LL y2)
{
return A(x1,x2)*A(y1,y2)%mod*2%mod;
}
LL AD(LL x1,LL x2,LL y1,LL y2)
{
return A(x1,x2)*B(y1,y2)%mod*2%mod;
}
LL BC(LL x1,LL x2,LL y1,LL y2)
{
return B(x1,x2)*A(y1,y2)%mod*2%mod;
}
LL BD(LL x1,LL x2,LL y1,LL y2)
{
return B(x1,x2)*B(y1,y2)%mod*2%mod;
}
int main()
{
int t;
cin>>t;
while(t--)
{
ans=0;
scanf("%lld%lld%lld%lld",&x1,&x2,&y1,&y2);
ans=(ans+A2(x1,x2,y1,y2))%mod;
ans=(ans+A2(y1,y2,x1,x2))%mod;
ans=(ans+B2(x1,x2,y1,y2))%mod;
ans=(ans+B2(y1,y2,x1,x2))%mod;
ans=(ans+AB(x1,x2,y1,y2))%mod;
ans=(ans+AB(y1,y2,x1,x2))%mod;
ans=(ans+AC(x1,x2,y1,y2))%mod;
ans=(ans+AD(x1,x2,y1,y2))%mod;
ans=(ans+BC(x1,x2,y1,y2))%mod;
ans=(ans+BD(x1,x2,y1,y2))%mod;
printf("%lld\n",ans);
// printf("%lld %lld\n",qmi(6,mod-2),qmi(2,mod-2));
}
return 0;
}