zoukankan      html  css  js  c++  java
  • SCNU 2015ACM新生赛初赛【1006. 3D打印】解题报告

     
          题目链接详见SCNU 2015新生网络赛 1006. 3D打印 。出题思路来自codevs 3288. 积木大赛,属于模拟题。
     
          首先我们把“选择从第L部分到第R部分”理解为“选择一段连续的部分”,OK,基本题意为:给定N个部件的高度,每次可以给连续的一段增加高度$1$,问至少需要几次增加高度的操作?
     
          不少人认为,直接模拟这个操作,循环给它$+1$,数加几次能达到要求高度就可以了。但很可惜这是会超时TLE哒。我们考虑极端情况,总共有$10^{5}$个部分,高度$h_{i}$是$0$和$10^{5}$相间的,这样总共需要$frac {10^{5}} {2} imes 10^{5} = 5 imes 10^{9}$次操作,复杂度为$O(NH)$,也就是说很可能一些同学的做法,会要进行$5 imes 10^{9}$次的循环,运行结果同样也是$5 imes 10^{9}$,不但超时,而且还超了$int$整型的范围。当然良心出题人并没有把这组数据放进去,数据做了奇怪的限定能保证结果不超过$int$,否则你应该需要拿long long__int64来存放结果(32位机下$int$和$long$都是$4$字节,一样的范围)。
     
          那怎么办呢?我们可以发现,如果$h_{i} > h_{i-1}$,那么总操作次数应要加上$h_{i} - h_{i-1}$,因为假定我在到达前面高度为$h_{i-1}$的部分的时候,已经总共操作了$t_{1}$次,如果当前部分比前面的还高,那么这个部分的下面$h_{i-1}$的高度已经被前面的操作完成了(尽量选择连续的一段增加高度),于是这里我只剩下了$t_{2} = h_{i} - h_{i-1}$的高度未完成。如果$h_{i} leq h_{i-1}$,则前面的操作肯定也把这部分顺便完成了,因此不需要再次计算。由于每次只需要比较$h_{i}$和$h_{i-1}$的大小关系,前面比较过的与后面的无关,所以只需要一个循环把数组遍历一次就可以了,复杂度为$O(N)$。
     
          代码如下(我是在读入的时候就完成判断,因此不需要数组保存了):
     1 #include <stdio.h>
     2 
     3 int main() {
     4     int T, N;
     5     scanf("%d", &T);
     6     while(T--) {
     7         int t = 0, x;
     8         long long res = 0;
     9         scanf("%d", &N);
    10         for(int i=0; i<N; i++) {
    11             scanf("%d", &x);
    12             if(x>t) res += x-t;
    13             t = x;
    14         }
    15         printf("%I64d
    ", res);
    16     }
    17     return 0;
    18 }
     
          在提交的代码中发现有同学想到了另一种方法,即寻找极大极小值的做法,复杂度同样为$O(N)$。比如我先找到一个极小值$rmin$,往后面找到一个极大值$rmax$,这样总次数只需加上$rmax - rmin$即可,因为极小值前面的部分已经计算过了,只需要考虑极小值到极大值之间的操作次数就好了。当然一开始时极小值为$0$,遍历结束后也要注意加上还没计算的部分,略微麻烦点,留给大家思考
     
          附:数据生成程序如下:
     1 #include <stdio.h>
     2 #include <random>
     3 using namespace std;
     4 default_random_engine g1;
     5 default_random_engine g2;
     6 lognormal_distribution<double> lognDis(9, 5);
     7 uniform_int_distribution<int> uiDis(1, 1E5);
     8 
     9 int main() {
    10     freopen("in.txt", "w+", stdout);
    11     int T = 10;
    12     printf("%d
    ", T);
    13     while(T--) {
    14         int N = lognDis(g1);
    15         if(N>1E5) N%=int(1E5);
    16         printf("%d
    ", N);
    17         for(int i=0; i<N; i++) {
    18             int Hi = uiDis(g2);
    19             printf("%d ", Hi);
    20         }
    21         puts("");
    22     }
    23     return 0;
    24 }
    Click To View Code
     
  • 相关阅读:
    『翻译』Android USB Host
    转--HC05-两个蓝牙模块间的通信
    情人节来了,教你个用 Python 表白的技巧
    最全的 pip 使用指南,50% 你可能没用过
    用 Sphinx 搭建博客时,如何自定义插件?
    一个 Vim 重度用户总结的 vim 超全指南
    每周分享五个 PyCharm 使用技巧(六)
    云计算与虚拟化入门通识
    Python静态方法,其实暗藏玄机
    每周分享五个 PyCharm 使用技巧(五)
  • 原文地址:https://www.cnblogs.com/BlackStorm/p/4988115.html
Copyright © 2011-2022 走看看