zoukankan      html  css  js  c++  java
  • zoj3435(莫比乌斯反演)

    题目链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3435

    题意: 给出一个三维坐标 (x, y, z), 问该点与 (1, 1, 1) 组成的长方体中有多少条经过点 (1, 1, 1) 的直线 .

    思路:  显然本题的难点是线段不能重复计算, 比如 (1, 1, 1) 到 (2, 2, 2) 和 (1, 1, 1) 到 (4, 4, 4) 同一条直线 .

    为了计算方便, 我们先将这个问题替换成它的等价问题: 求 (0, 0, 0), (x - 1, y - 1 , z - 1) 组成的长方体中有多少条经过 (0, 0, 0) 的直线 .

    通过画图可以发现当且仅当点 (j, k, l) 满足 gcd(j, k, l) = 1 时累计直线 (0, 0, 0), (j, k, l) 刚好能累加到所有直线并且不会重复计算 .

    然后我们将满足条件的直线分为 3 部分:

    1. 从 (0, 0, 0) 出发的 3 条棱;

    2. 从 (0, 0, 0) 出发的 3 个表面;

    3. 从 (0, 0, 0) 出发到长方体内部的直线;

    对于 1, 显然满足条件的直线为 3 条;

    对于 2, 满足条件的直线数目为 gcd(j, k) = 1 的直线数目加 gcd(j, l) = 1 的直线数目加 gcd(k, l) = 1 的直线数目, 其中 1 <= j <= x -1, 1 <= k <= y - 1, 1 <= l <= z -1;

    对于 3, 满足条件的直线数目为 gcd(j, k, l) = 1 的直线数目, 其中 1 <= j <= x -1, 1 <= k <= y - 1, 1 <= l <= z -1;

    显然对于上面的计算部分都可以用莫比乌斯反演在线性时间内完成 .

    代码:

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <string.h>
     4 #define ll long long
     5 using namespace std;
     6 
     7 const int MAXN = 1e6 + 10;
     8 
     9 bool check[MAXN];
    10 int prime[MAXN], mu[MAXN], sum[MAXN];
    11 
    12 void Moblus(void){
    13     memset(check, false, sizeof(check));
    14     int tot = 0;
    15     mu[1] = 1;
    16     sum[1] = 1;
    17     for(int i = 2; i < MAXN; i++){
    18         if(!check[i]){
    19             prime[tot++] = i;
    20             mu[i] = -1;
    21         }
    22         for(int j = 0; j < tot && prime[j] * i < MAXN; j++){
    23             check[prime[j] * i] = true;
    24             if(i % prime[j] == 0){
    25                 mu[i * prime[j]] = 0;
    26                 break;
    27             }else mu[i * prime[j]] = -mu[i];
    28         }
    29         sum[i] = sum[i - 1] + mu[i];
    30     }
    31 }
    32 
    33 ll solve(int x, int y){
    34     ll ans = 0;
    35     if(x > y) swap(x, y);
    36     for(int i = 1, la = 0; i <= x; i = la + 1){
    37         la = min(x / (x / i), y / (y / i));
    38         ans += (ll)(sum[la] - sum[i - 1]) * (x / i) * (y / i);
    39     }
    40     return ans;
    41 }
    42 
    43 ll solve(int x, int y, int z){
    44     ll ans = 0;
    45     if(x > y) swap(x, y);
    46     if(x > z) swap(x, z);
    47     for(int i = 1, la = 0; i <= x; i = la + 1){
    48         la = min(min(x / (x / i), y / (y / i)), z / (z / i));
    49         ans += (ll)(sum[la] - sum[i - 1]) * (x / i) * (y / i) * (z / i);
    50     }
    51     return ans;
    52 }
    53 
    54 int main(void){
    55     Moblus();
    56     int x, y, z;
    57     while(~scanf("%d%d%d", &x, &y, &z)){
    58         x--;
    59         y--;
    60         z--;
    61         ll ans = 3;
    62         ans += solve(x, y);
    63         ans += solve(x, z);
    64         ans += solve(y, z);
    65         ans += solve(x, y, z);
    66         printf("%lld
    ", ans);
    67     }
    68     return 0;
    69 }
    View Code
  • 相关阅读:
    android app记录执行日志 捕获奔溃异常 ,存储日志到文件
    对扩展openflow协议的一点思考
    Echarts柱状图
    python实现插入排序
    MyBatis -- 对表进行增删改查(基于注解的实现)
    pat解题报告【1082】
    [Swift]LeetCode974. 和可被 K 整除的子数组 | Subarray Sums Divisible by K
    [Swift]LeetCode976. 三角形的最大周长 | Largest Perimeter Triangle
    [Swift]LeetCode345. 反转字符串中的元音字母 | Reverse Vowels of a String
    [Swift]LeetCode343. 整数拆分 | Integer Break
  • 原文地址:https://www.cnblogs.com/geloutingyu/p/7250128.html
Copyright © 2011-2022 走看看