zoukankan      html  css  js  c++  java
  • 例21-8 删数

    题目:给定(n)个整数。对于其中的每个数(a[i]),求出删去它以后剩下的所有数的最大公约数,(n<=10^6)

    对于删去(a[i])后的数组,显然剩下的数一定是(a[1])(a[i-1])(前缀)和(a[i+1])(a[n])(后缀)。这意味着,如果用(Left[i])表示(a[1])(a[i])的最大公约数,(Right[i])表示(a[i])(a[n])的最大公约数,那么删除(a[i])以后的答案就是((Left[i-1],Right[i+1])),可以快速求出。

    1、以空间换时间,算完的结果保存下来,下次可以复用。

    2、最大公约数有这样的性质,可以几个人先算,算完的就有用,可以接着算。

    3、左端数组,需要从左向右算。右端数组,需要从右向左算。为什么这样呢?举个栗子,自已想想原因。

    #include <bits/stdc++.h>
    
    using namespace std;
    const int N = 110;
    int a[N];
    int Left[N], Right[N];
    
    //最大公约数,辗转相除法
    int gcd(int a, int b) {
        if (b == 0) return a;
        return gcd(b, a % b);
    }
    
    /**
     * 测试数据:
     5
     12 36 24 18 48
     结果:6 6 6 12 6
     */
    
    int main() {
        int n;
        cin >> n;
        //读入数据
        for (int i = 1; i <= n; i++) cin >> a[i];
        //类似于递推式获取前1~(i-1)的最大公约数记录到Left[i]中。
        for (int i = 1; i <= n; i++) Left[i] = gcd(Left[i - 1], a[i]);
        //类似于递推式获取后n~(i+1)的最大公约数记录到Right[i]中。
        for (int i = n; i >= 1; i--) Right[i] = gcd(a[i], Right[i + 1]);
        //根据性质3,可以通过左边最大公约和右边最大公约计算出去掉当前数字的最大公约
        for (int i = 1; i <= n; i++) cout << gcd(Left[i - 1], Right[i + 1]) << " ";
        //时间分析:O(3*n)
        //如果去掉每一个,分别进行重新计算的话,外层循环贡献n,内层还需要一层遍历所有剩余数字,可以认为是O(N^2)级。
        //这样通过性质3,就可以实现平方级别时间复杂度到线性复杂度的进化。
        //究其原因,就是空间换时间,把已知的结果保存下来,避开了重复的计算。
        return 0;
    }
    
  • 相关阅读:
    Cartographer源码阅读(1):程序入口
    ROS开发与常用命令
    实时Cartographer测试(1)
    Cartographer安装
    ROS安装(2)
    Linux学习和ROS安装(1)
    无法启动程序
    c# 获取端口的连接数,网站的连接数
    SignarL服务器端发送消息给客户端的几种情况
    c#操作IIS之IISHelper
  • 原文地址:https://www.cnblogs.com/littlehb/p/15193928.html
Copyright © 2011-2022 走看看