纪念一下这场膜你赛中唯一AC的题。
题面:
小 K 翻看高中时期留下的数学笔记,发现了一道题:
给定四个正整数 x1,x2,y1,y2,计算
x2∑i=x1y2∑j=y1(⌊ix1⌋+⌊x2i⌋+⌊jy1⌋+⌊y2j⌋)2
可是笔记上没有解答,由于上了大学之后就再也没碰过数学,小 K 现在不会做了,于是他来请教你。
由于答案可能很大,你只要输出答案对 109+7 取模后的值。
数据范围:
对于 30% 的数据,T=10,x2−x1≤103,y2−y1≤103
对于 60% 的数据,T=10,x2−x1≤106,y2−y1≤106
对于 100%的数据,1≤T≤100,1≤x1≤x2≤109,1≤y1≤y2≤109。
solution:
对于 30pts ,暴力 O(n2) 枚举
无脑推柿子。
先把字母换得好看点:
ans=b∑i=ad∑j=c(⌊ia⌋+⌊bi⌋+⌊jc⌋+⌊dj⌋)2
经典套路,裂项求和:
ans1=b∑i=ad∑j=c2(⌊ia⌋+⌊bi⌋)(⌊jc⌋+⌊dj⌋)
ans2=b∑i=ad∑j=c(⌊ia⌋+⌊bi⌋)2
ans3=b∑i=ad∑j=c(⌊ic⌋+⌊di⌋)2
则有:
ans=ans1+ans2+ans3
对于三项分别进行处理:
对于 ans1 ,适当变换求和顺序:
ans1=2b∑i=a(⌊ia⌋+⌊bi⌋)d∑j=c(⌊jc⌋+⌊dj⌋)
对于 ans2 和 ans3,发现有一层和式可以直接扔掉:
ans2=b∑i=a(⌊ia⌋+⌊bi⌋)2×(d−c+1)
ans3=d∑i=c(⌊ic⌋+⌊di⌋)2×(a−b+1)
处理到这步时,我们发现已经可以 O(n) 进行求解,60pts 到手。
但如果我们追求更高的分数,还要继续优化:
ans1=2b∑i=a(⌊ia⌋+⌊bi⌋)d∑j=c(⌊jc⌋+⌊dj⌋)
ans2=b∑i=a(⌊ia⌋2+2⌊ia⌋⌊bi⌋+⌊bi⌋2)×(d−c+1)
ans3=d∑i=c(⌊ic⌋2+2⌊ic⌋⌊di⌋+⌊di⌋2)×(a−b+1)
令
f1(n,m)=m∑i=n⌊in⌋
f2(n,m)=m∑i=n⌊mi⌋
f3(n,m)=m∑i=n⌊in⌋2
f4(n,m)=m∑i=n⌊mi⌋2
则有:
ans1=2×(f1(a,b)+f2(a,b))×(f1(c,d)+f2(c,d))
ans2=(d−c+1)f3(a,b)+(d−c+1)f4(a,b)+2(d−c+1)b∑i=a⌊ia⌋⌊bi⌋
ans3=(b−a+1)f3(c,d)+(b−a+1)f4(c,d)+2(b−a+1)d∑i=c⌊ic⌋⌊di⌋
对于 ans2 和 ans3 的最后一项,回顾一下上次讲数论分块时提到的(不知道的看这里):
有这样一个和式:
n∑i=1fi⌊ni⌋
我们就可以通过数论分块来求解她。
那么在数论分块的过程中,对于块 [l,r] ,她的贡献是:
ans=⌊ni⌋×(Sr−Sl−1)
带入到 ∑di=c⌊ic⌋⌊di⌋ 中,前缀和 S 是什么?
我们惊喜的发现 Sr−Sl−1 就是 f1(l−1,r)
那么只要能快速求出 f1,f2,f3,f4 ,这个问题就解决了。
对于 f2 和 f4,是个显然的数论分块b有坑,因为边界不等于分子,不能省略对边界的特判)。
对于 f1 和 f3,乍一看不可做,但是我们考虑这个东西的本质:
⌊ix⌋(a≤i≤b)
i 原本是一个等差数列,除以了一个 x 后:
1,1,1,2,2,2,3,3,3,4,4,4…
变成了每个数连续出现 x 遍的等差数列!
不妨就处理这个等差数列,最后乘上 x。
序列 ⌊ix⌋(a≤i≤b),我们根据值进行分类,会有 ⌊b−a+1x⌋ 个整块,每块 x 个数值相同;最后还有 (b−a+1)modx 个散数,值为 ⌊bx⌋。
那么接下来就好处理了:
对于 f1,直接套等差数列求和公式:
f1(a,b)=⌊b−a+1x⌋(⌊b−a+1x⌋+1)÷2+((b−a+1)modx)⌊bx⌋
这个柿子可以 O(1) 求出。
对于 f3,学过小学奥数的我们知道平方和公式:
f3(a,b)=⌊b−a+1x⌋(⌊b−a+1x⌋+1)(2⌊b−a+1x⌋+1)÷6+((b−a+1)modx)⌊bx⌋2
这个柿子也可以 O(1) 求出。
大功告成!代码也很好打,没有啥高级的数论算法。(就是细节挺多的。)
复杂度为 O(T√n×巨大常数),瓶颈在于多次数论分块。
放一下代码:
已经把象征着血泪的调试语句删掉了
这份代码常数很大,请吸臭氧食用。
#pragma GCC optimize(3)
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
#define maxn 1005
#define rg register
#define ll long long
#define inf 0x7f7f7f7f
#define djq 1000000007
inline void file(){
freopen("test.in","r1",stdin);
}
char buf[1<<21],*p1=buf,*p2=buf;
inline int getc(){
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;
}
inline int read(){
rg int ret=0,f=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=1;ch=getchar();}
while(isdigit(ch)){ret=ret*10+ch-48;ch=getchar();}
return f?-ret:ret;
}
char buffer[1<<25];
int q1=-1;
const int q2=(1<<25)-1;
inline void flush(){ fwrite(buffer,1,q1+1,stdout),q1=-1; }
inline void putc(const char &x){ if(q1==q2) flush(); buffer[++q1]=x;}
void wrtn(int x){
static char buf[15];
static int len=-1;
if(x>=0){ do{ buf[++len]=x%10+48,x/=10; }while(x);
}else{ putc('-'); do{ buf[++len]=-(x%10)+48,x/=10; }while(x);}
while(len>=0){ putc(buf[len]), --len; }
}
int _,a,b,c,d,inv6=166666668;
ll sum1,sum,sum3,sum2;
inline int pfh(int n){
return 1ll*n*(n+1)%djq*(2*n+1)%djq*inv6%djq;
}
inline int work1(int n,int m){
ll ret=0;
for(rg int l=1,r=0;l<=n;l=r+1){
r=m/l?min(m/(m/l),n):n;
ret+=1ll*(r-l+1)*(m/l)%djq;
ret%=djq;
}
return ret;
}
inline int work2(int a,int b){
if(b<a) return 0;
int tmp=(b-a+1)/a;
ll ret=1ll*tmp*(tmp+1)/2%djq*a%djq;
ret+=1ll*b/a*((b-a+1)%a)%djq;
ret%=djq;
return ret;
}
inline int work3(int n,int m){
ll ret=0;
for(rg int l=1,r=0;l<=n;l=r+1){
r=m/l?min(m/(m/l),n):n;
ret+=1ll*(r-l+1)*(m/l)%djq*(m/l)%djq;
ret%=djq;
}
return ret;
}
inline int work4(int a,int b){
if(b<a) return 0;
ll ret=1ll*pfh((b-a+1)/a)*a%djq;
ret+=1ll*(b/a)*(b/a)%djq*((b-a+1)%a)%djq;
ret%=djq;
return ret;
}
inline int work5(int a,int b){
ll ret=0;
for(rg int l=a,r=0;l<=b;l=r+1){
r=b/(b/l);
ret=ret+1ll*(work2(a,r)-work2(a,l-1)+djq)*(b/l)%djq;
ret%=djq;
}
return ret;
}
int main(){
_=read();
while(_--){
a=read(); b=read(); c=read(); d=read();
sum=sum1=sum2=sum3=0;
sum=1ll*work2(c,d)+work1(d,d)-work1(c-1,d)+djq;
sum%=djq;
sum1=1ll*work2(a,b)+work1(b,b)-work1(a-1,b)+djq;
sum1%=djq;
sum1*=sum*2; sum1%=djq;
sum2=1ll*work4(a,b)+work3(b,b)-work3(a-1,b)+2*work5(a,b)+djq;
sum2%=djq; sum2*=(d-c+1)%djq; sum2%=djq;
sum3=1ll*work4(c,d)+work3(d,d)-work3(c-1,d)+2*work5(c,d)+djq;
sum3%=djq; sum3*=(b-a+1)%djq; sum3%=djq;
wrtn((sum1+sum2+sum3)%djq); putc('\n');
}
flush();
return 0;
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人