洛谷P3636 曲面

来源:互联网 发布:华语乐坛现状知乎 编辑:程序博客网 时间:2024/05/20 16:09

链接

  https://www.luogu.org/problem/show?pid=3636

题解

  题目大意:对于所有k[1,N],求满足xyz=k的整数x,y,z(|x|+|y|+|z|)2之和。
  看起来很麻烦,我用了很多种方法都不行,最后还是找对了路子。首先如果我们枚举k的话会很慢,所以条件可以改成:xyzN,求这样的(x,y,z)(|x|+|y|+|z|)2之和。忘了加一句,答案应该是对第一卦限(x>0,y>0,z>0)做完之后的结果乘以4。
  

ans=4×x=1Ny=1Nxz=1Nxy(x+y+z)2

  呃似乎很慢…可以看到对于给定的xy,后面的Nxyz=1(x+y+z)2就是(x+y+1)2+(x+y+2)2+...+(x+y+Nxy)2,这个就是平方和的连续一段,直接用平方和公式。设f(n)=n(n+1)(2n+1)6,则答案
  
ans=4×x=1Ny=1Nx[f(x+y+Nxy)f(x+y)]

  这样是O(N1+N2+N3+...+NN)=O(NlogN)的。可以过60分,到这里我就卡住了,不会优化…打完T3的暴力之后又回来看,我换了一种思路。
  如果令x<y<z,那么结合xyzN的条件,可以得到x<N3,咦这似乎可以降复杂度,于是继续写,得到当x<y<z
  
ans1=x<N3y<Nx[f(x+y+Nxy)f(x+y+y)]

  (这里的f(x+y+y)写成f(x+y+(y+1)1)可能好理解些)
  那么这个肯定是O(N3logN3)的。
  上面是三个数字互不相同,在考虑有两个相同并且和第三个不同的,即x=yz
  
ans2=x<N[f(x+x+Nx2)f(x+x)](x+x+x)2[if(x3N)]

  最后考虑x=y=z
  
ans3=x=1N3(x+x+x)2

  然后
ans=4×(6ans1+3ans2+ans3)

  总的时间复杂度是O(N)
  听说正解是杜教筛啥的,好厉害的样子…我不会

代码

#include <cstdio>#include <algorithm>#define mod 10007ll#define lim 100000000000000000ll#define ll long longusing 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;}
1 0