Loading

3148. 【GDKOI2013】琪露诺的完美算法课

Description

琪露诺的完美算法课开课啦!今天上的是几何课哦!

“直角三角形就是有一个角是 90 度的三角形哦!而且假如最长的那条边边长是 c,剩下的两条边长度分别是a 和 b,它们就一定会满足 a^2+b^2=c^2 哦!比如 (3,4,5) 哦!还有 (4,3,5) 哦!还有 (4,7,8) 哦!”琪露诺戴着眼镜挥着教鞭说道。

“笨蛋,(4,7,8) 是直角三角形吗?”不知从哪里传来的声音。

于是琪露诺算了一下,发现 4^2+7^2=65<>64。

“你...你才是笨蛋呢!比那边大 1 的话...也和直角三角形差不多!都是直角三角形!”

“那对于三条边边长都为整数的三角形 (a,b,c),如果 a 在某一个范围内,你所谓的‘直角三角形’有多少个呢?”天之音继续提问到。

你能帮他算出来吗?

Solution

先给出一些引理:

  1. 若用 \(d(x)\) 表示 \(x\) 的因数个数,并且 \(x=\Pi {p_i}^{c_i}\)(其中 \(p_i\) 都是质数),那么 \(d(x)=\Pi(c_i+1)\)

    证明:每个质因数有 \(c_i+1\) 种选择,不同的选择可以组成不同的因数,用乘法原理易证。

  2. \(n=x\times y[\gcd(x,y)=1]\),那么 \(d(n)=d(x)\times d(y)\)

    证明:\(x\)\(y\) 都是 \(n\) 的因数,所以组成 \(n\) 的质因数 \(x\)\(y\) 中有且仅有一个全部拥有(因为互质),再根据乘法结合律可以证明。

有了以上两个引理后,我们考虑对题目中的条件进行转换。

已知 \(a^2+b^2=c^2\) 或者 \(a^2+b^2-1=c^2\),那么分开来做。

移项并因式分解得 \(a^2=(c+b)(c-b)\) 或者 \((a+1)(a-1)=(c+b)(c-b)\),而 \(c+b\)\(c-b\) 同奇同偶,所以就是要将 \(a^2\) 或者 \((a+1)(a-1)\) 分成同奇同偶的因数。


先考虑简单版:

\(f(x)\) 表示将 \(x\) 分成同奇同偶的因数的方案数(\(x\le 10^7\))。

假如 \(x\) 是奇数,那么只需要将 \(x\) 的因数中任取一个即可,所以 \(f(x)=\frac{d(x)}{2}\)

假如 \(x\) 是偶数,设 \(x=2^y\times p\),而 \(p\) 是个奇数,所以我们可以先选择 \(p\) 的因数,再乘上一定量的 2。为了保证 2 在分成的两个因数中都存在,所以 \(y\ge 2\),因此 \(x\) 一定要是 4 的倍数,如果不是 \(f(x)=0\)

\(y\ge 2\) 时,\(f(x)=\frac{d(p)\times(y-1)}{2}=\frac{d(p)\times d(2^{y-2})}{2}=\frac{d(p\times 2^{y-2})}{2}=\dfrac{d(\frac{x}{4})}{2}\)

现在考虑求 \(f(x^2)\)\(x\le 10^7\))。首先若 \(x=\Pi {p_i}^{c_{i}}\),那么 \(x^2=\Pi {p_i}^{2c_i}\),所以 \(d(x^2)=\Pi(2c_i+1)\)

那么接下来和求 \(f(x)\) 类似。若 \(x\) 为奇数,\(f(x^2)=\frac{d(x^2)}{2}\)。若 \(x\) 为偶数,\(f(x^2)=\dfrac{d(\frac{x^2}{4})}{2}=\dfrac{d(\frac{x}{2})}{2}\)(注意偶数的时候没有 \(x\) 是 4 的倍数这条限制,因为只要 \(x\) 是偶数,那么 \(x^2\) 一定是 4 的倍数)。


到此我们解决了 \(a^2\) 这一部分,下面处理 \((a+1)(a-1)\)

如果 \(a\) 是偶数,那么 \(a+1\)\(a-1\) 一定互质。此时 \(d((a+1)(a-1))=d(a+1)\times d(a-1)\),然后就可以求 \(f(x)\)\(x\) 是奇数)的做法求出 \(f((a+1)(a-1))\)

如果 \(a\) 是奇数,那么 \(a+1\)\(a-1\) 都是偶数,并且 \(\gcd(a+1,a-1)=2\),所以 \((a+1)(a-1)\) 是 4 的倍数,因此 \(f((a+1)(a-1))=\dfrac{d(\frac{(a+1)(a-1)}{4})}{2}=\dfrac{d(\frac{a+1}{2}\times \frac{a-1}{2})}{2}=\dfrac{d(\frac{a+1}{2})\times d(\frac{a-1}{2})}{2}\)


至此两部分都处理完。而 \(d(x)\)\(d(x^2)\) 可以用欧拉筛在 \(\mathcal O(n)\) 的时间内预处理出,然后枚举 \(a\),对于每个 \(a\),求答案是 \(\mathcal O(1)\) 的,因此总复杂度 \(\mathcal O(n)\)

Code

#include<cstdio>
#define ll long long
#define N 10000005
using namespace std;
int l,r,a,b,ans,prime[N],d[N],d2[N],cnt[N];
bool bj[N];
ll x;
int main()
{
    d[1]=1;d2[1]=1;
    for (int i=2;i<=N;++i)
    {
        if (!bj[i]) 
        {
            prime[++prime[0]]=i;
            d[i]=2;
            d2[i]=3;
            cnt[i]=1;
        }
        for (int j=1;j<=prime[0];++j)
        {
            if (prime[j]*i>N) break;
            bj[prime[j]*i]=true;
            if (i%prime[j]==0)
            {
                d[i*prime[j]]=d[i]/(cnt[i]+1)*(cnt[i]+2);
                d2[i*prime[j]]=d2[i]/(2*cnt[i]+1)*(2*(cnt[i]+1)+1);
                cnt[i*prime[j]]=cnt[i]+1;
                break;
            }
            else
            {
                d[i*prime[j]]=d[i]*d[prime[j]];
                d2[i*prime[j]]=d2[i]*d2[prime[j]];
                cnt[i*prime[j]]=1;
            }
        }
    }
    scanf("%d%d",&l,&r);
    for (int i=l;i<=r;++i)
    {
        if (i%2==1) ans+=d2[i]/2;
        if (i%2==0) ans+=d2[i/2]/2;
        if (i%2==1) ans+=d[(i+1)/2]*d[(i-1)/2]/2;
        if (i%2==0) ans+=d[i+1]*d[i-1]/2;
    }
    printf("%d\n",ans);
    return 0;
}
posted @ 2022-02-11 21:02  Thunder_S  阅读(38)  评论(0编辑  收藏  举报