题解:P10584 [蓝桥杯 2024 国 A] 数学题
upd on 2024.6.27:怎么给我题解撤下了,改了下之前写错的地方
题意:求所有满足
做法:
考虑对于一组合法的
可以理解为
而此时对于一个
那我们换一个角度去计数,问题转化为求
后面这两个东西可以整除分块,端点数量是
此时求和中
在进行整除分块之后,现在的问题变成了查询区间内无平方因子数的个数。
你可以按照上面那题的题解区做法,但是那样需要预处理
我们查询那题最优解,得到这样一个做法:Link。
简单来说,就是
Dirichlet 双曲线法可以参考我找到的一篇知乎文章,下面是代入上面式子的具体推导:
假设存在
取
其它细节可以自己参考前两篇文章,因为我实际上直接硬写就过了。
实现:
ull calc2(ll n){// 计算 1~n 非平方因子数的个数
if(n==0)return 0;
ll T=cbrt(n);
while((T+1)*(T+1)*(T+1)<=n)T++;
ull ans=-calc1(T)*T;// 先算后面的部分
for(ull i=1;i<=T;i++)ans+=Mu[i]*(n/(i*i))+calc1(SQRT(n/i));//两个同时计算,calc1 是 mu 前缀和,直接杜教筛
return ans;
}
void __SOLVE__(ll _case){
init(3000000);//线性筛预处理小范围的 mu 和前缀和
cin>>n>>m;
for(ull l=1,r,x;l<=n;l=r+1){// 计算断点
ps.push_back(l);
x=SQRT(n/l);
r=n/(x*x);
}
for(ull l=1,r,x;l<=m;l=r+1){
ps.push_back(l);
x=SQRT(m/l);
r=m/(x*x);
}
ps.push_back(1),ps.push_back(min(n,m)+1);
sort(all(ps)),ps.erase(unique(all(ps)),ps.end());
ull ans=0;
for(int i=0;i<ps.size()-1;i++){
ull l=ps[i],r=ps[i+1]-1;
ans+=(calc2(r)-calc2(l-1))*(ull)(SQRT(n/l))*(ull)(SQRT(m/l));// 对于每个区间内计算答案
}
cout<<ans<<"\n";
}