• ZOJ3435


    题意略。

    思路:

    将每一个点的坐标 (x,y,z) 与 (1,1,1) 相减,得到向量 (x - 1,y - 1,z - 1) 我们实际上就是要求出 这样互质的三元组有多少对就行了。

    我们把这个长方体分成3部分:

    1.三条坐标棱                                      2.在坐标棱上的三个表面(除去坐标棱)                                3.长宽高分别为[L - 1,W - 1,H - 1]的长方体

    三条坐标棱我们只要开3枪,就可以贯穿这个部分,ans += 3。

    至于2和3,我们可以用莫比乌斯的第二类反演来解决。

    在用莫比乌斯反演时,如果我们一 一枚举因子,就会T,我们来考虑一个sqrt(n)的优化。

    比如说19这个数:

    19 / 1 = 19,19 / 2 = 9,19 / 3 = 6,19 / 4 = 4,19 / 5 = 3,19 / 6 = 3,19 / 7 = 2,19 / 8 = 2,19 / 9 = 2,19 /10 = 1,......,19 / 19 = 1

    在进行反演时,我们必然是通过枚举分母,计算出F(i) = (L / i) * (W / i) * (H / i)。

    然而可以发现,7,8,9只要枚举一个就行,10~19也只需要枚举一个就行,如果我们用sum[ i ] 来维护mu[ i ]的前缀和,

    那么ans += mu[ 7 ] * 19 / 7 + mu[ 8 ] * 19 / 8 + mu[ 9 ] * 19 / 9   等价于  ans += (sum[ 9 ] - sum[ 6 ]) * 19 / 7。

    我们知道对于任意一个数x >= a * b,它的这种小于它且可以产生不同b的a最多有2 * sqrt(x)个。

    详见代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const LL maxn = 1000005;
    
    LL l,w,h;
    bool check[maxn];
    LL prime[maxn];
    LL mu[maxn],sum[maxn];
    
    void mobius(){
        memset(check,false,sizeof(check));
        mu[1] = 1;
        sum[1] = 1;
        int tot = 0;
        for(LL i = 2;i < maxn;++i){
            if(!check[i]){
                prime[tot++] = i;
                mu[i] = -1;
            }
            for(int j = 0;j < tot;++j){
                if(i * prime[j] > maxn) break;
                check[i * prime[j]] = true;
                if(i % prime[j] == 0){
                    mu[i * prime[j]] = 0;
                    break;
                }
                else mu[i * prime[j]] = -mu[i];
            }
            sum[i] = sum[i - 1] + mu[i];
        }
    }
    
    int main(){
        mobius();
        while(scanf("%lld%lld%lld",&l,&w,&h) == 3){
            LL ans = 0;
            LL len = min(l,min(w,h)),last;
            for(LL i = 1;i < len;i = last + 1){
                LL a = (l - 1) / i,b = (w - 1) / i,c = (h - 1) / i;
                last = min((l - 1) / a,min((w - 1) / b,(h - 1) / c));
                ans += (sum[last] - sum[i - 1]) * (a * b * c);
            }
            len = min(l,h);
            for(LL i = 1;i < len;i = last + 1){
                LL a = (l - 1) / i,b = (h - 1) / i;
                last = min((l - 1) / a,(h - 1) / b);
                ans += (sum[last] - sum[i - 1]) * (a * b);
            }
            len = min(l,w);
            for(LL i = 1;i < len;i = last + 1){
                LL a = (l - 1) / i,b = (w - 1) / i;
                last = min((l - 1) / a,(w - 1) / b);
                ans += (sum[last] - sum[i - 1]) * (a * b);
            }
            len = min(w,h);
            for(LL i = 1;i < len;i = last + 1){
                LL a = (w - 1) / i,b = (h - 1) / i;
                last = min((w - 1) / a,(h - 1) / b);
                ans += (sum[last] - sum[i - 1]) * (a * b);
            }
            ans = ans + 3;
            printf("%lld
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    大数相加和快速相乘
    (转)直线分割平面 与 平面分割区域 问题
    8.3水了一天
    8.2数论(1)
    7.31 基本算法1.2
    7.31 基本算法1.1
    《GSoC 2019小结》&《买车小记》By Ray Guo
    【笔试题】中国电信天翼智慧家庭2020春季校园招聘
    TinyMCE主题的文章目录没法点击页内跳转
    【毕设】答辩如何准备?本科毕业论文如何撰写文献综述?
  • 原文地址:https://www.cnblogs.com/tiberius/p/9309407.html
Copyright © 2020-2023  润新知