链接
https://www.luogu.org/problem/show?pid=3636
题解
题目大意:对于所有
k∈[1,N]
,求满足
xyz=k
的整数
x,y,z
的
(|x|+|y|+|z|)2
之和。
看起来很麻烦,我用了很多种方法都不行,最后还是找对了路子。首先如果我们枚举
k
的话会很慢,所以条件可以改成:
ans=4×∑x=1N∑y=1⌊Nx⌋∑z=1⌊Nxy⌋(x+y+z)2
呃似乎很慢…可以看到对于给定的 x 和
ans=4×∑x=1N∑y=1⌊Nx⌋[f(x+y+⌊Nxy⌋)−f(x+y)]
这样是 O(N1+N2+N3+...+NN)=O(NlogN) 的。可以过60分,到这里我就卡住了,不会优化…打完T3的暴力之后又回来看,我换了一种思路。
如果令 x<y<z ,那么结合 xyz≤N 的条件,可以得到 x<N−−√3 ,咦这似乎可以降复杂度,于是继续写,得到当 x<y<z 时
ans1=∑x<N√3∑y<Nx[f(x+y+⌊Nxy⌋)−f(x+y+y)]
(这里的 f(x+y+y) 写成 f(x+y+(y+1)−1) 可能好理解些)
那么这个肯定是 O(N−−√3logN−−√3) 的。
上面是三个数字互不相同,在考虑有两个相同并且和第三个不同的,即 x=y≠z
ans2=∑x<N√[f(x+x+⌊Nx2⌋)−f(x+x)]−(x+x+x)2[if(x3≤N)]
最后考虑 x=y=z 的
ans3=∑x=1N√3(x+x+x)2
然后
ans=4×(6ans1+3ans2+ans3)
总的时间复杂度是 O(N−−√) 。
听说正解是杜教筛啥的,好厉害的样子…我不会
代码
#include <cstdio>
#include <algorithm>
#define mod 10007ll
#define lim 100000000000000000ll
#define ll long long
using namespace std;
ll inv[100];
inline ll f(ll n){return n*(n+1)%mod*(2*n+1)*inv[6]%mod;}
inline ll sqr(ll x){return x*x;}
inline ll pow(ll a, ll b)
{
ll ans, t;
for(ans=1,t=a;b;b>>=1,t=t*t%mod)if(b&1)ans=ans*t%mod;
return ans;
}
void init()
{
ll i;
for(i=1;i<=10;i++)inv[i]=pow(i,mod-2)%mod;
}
ll work(ll N)
{
ll x, y, ans=0, t;
//x<y<z
t=0;
for(x=1;x*x*x<N;x++)
{
for(y=x+1;y<N/x/y;y++)
{
t+=f(x+y+(N/x/y))-f(x+y+y);
if(t>lim)t%=mod;
}
}
ans+=t*6%mod;
//x=y!=z
t=0;
for(x=1;x*x<=N;x++)
{
t=t+f(x+x+N/x/x)-f(x+x);
if(x*x*x<=N)t=t-sqr(x+x+x);
if(t>lim)t%=mod;
}
ans+=t*3%mod;
//x=y=z
t=0;
for(x=1;x*x*x<=N;x++)
{
t+=sqr(x+x+x);
if(t>lim)t%=mod;
}
ans+=t%mod;
return ans%mod;
}
int main()
{
ll a, b, ans;
scanf("%lld%lld",&a,&b);
init();
if(a>b){printf("0");return 0;}
ans=work(b)-work(a-1);
printf("%lld",(ans*4%mod+mod)%mod);
return 0;
}