• SCAU 10675 ACMer不得不知道的事儿(二)


    10675 ACMer不得不知道的事儿(二)

    时间限制:1000MS  内存限制:65535K 提交次数:0 通过次数:0

    题型: 编程题   语言: 无限制

    Description

        作为一个入门的ACMer,在参加比赛之前,你势必要了解算法的一些基本概念,比如复杂度。
        ACM的题目,只要不是a+b级别的,总会需要一定的算法来解决,即使是枚举,
        也是叫做穷举算法。
    
        一个算法的好坏,由它的复杂度来衡量,复杂度越高,算法越低效。
        复杂度包括不限于时间复杂度、空间复杂度和编码复杂度,即其花费的时间、空间(即内存使用等)还有实现的难度。
    第三个在做研究的时候不一定会考虑,但ACM赛制是5个小时内决胜负,编码复杂度也是至关重要的一个因素。
    
       一、时间复杂度
        通俗讲时间复杂度就是用来衡量算法执行的时间的,它和问题的规模(通常用n表示,如果问题规模和不止一个变量有关,
    那用n,m,k等等表示)有关,规模越大,所花费的时间越长。越高效的算法,在n增长的时候,执行时间增加的越少。
    例如求1..n的和,下面有三种写法:
    
    普通写法是:
    int sum=0,i;
    for(i=1;i<=n;i++)
    sum+=i;
        我们说它的时间复杂度是O(n)。因为运行一次,必须执行一次n长度的循环,n越大时间越大。对于每次循环,它需要执行
    一次i++,一次sum+=i,一次判断是否i<=n,可以说复杂度是O(3n),但是通常常数不被计入到复杂度的计算中,所以简化为O(n)。
    
    文艺写法:
    int sum=n*(n+1)/2;
    复杂度O(1),很明显运行一次只需要执行一次运算操作。
    
    2B写法:
    int sum=0,i,j;
    for(i=1;i<=n;i++)
    {
    	for(j=1;j<=i;j++)
    		sum++;
    }
        嗯,很暴力很2B的O(n^2)复杂度,你懂的。
    
        说到这里相信你已经对时间复杂度有了一定的了解了。
    
    二、空间复杂度
        所谓空间复杂度就是你用的内存的大小,简单说就是你用了多少变量开了多大的数组,malloc了多少内存,综合起来就是了,
    这点比较简单,就不一一赘述。
    
    三、编码复杂度
        编码复杂度和你实现算法所需要的时间有关,而且有时候和时间复杂度也有一定关系,但不是越高级的算法越难实现,
    像刚才的例子就是时间复杂度高了,编码复杂度也跟着高了。
    
        当你对算法有了一定了解,在ACM上收获了不少知识之后,你甚至能在一些场合很轻松地解决掉一些问题,
    并BS一些动手能力不强的人。
    
        就好比某个牛津计算机系从本科读到博士还经常考第一的人,可以花15分钟的时间写出类似这样的代码,
    来求一个数组里面,有多少数比它左边的数都要大:
    cnt=0;
    for(i=0;i<n;i++)
    {
        for(j=0;j<i;j++)
        {
            if(a[i]<a[j])
                break;
        }
        if(j==i)
            b[i]=1;
        else
            b[i]=0;
    }
    for(i=0;i<n;i++)
    {
        if(b[i]==1)
        cnt++;
    }
    printf("%d\n",cnt);
    
        这样写法的复杂度相信大家可以估算的出来,那么,我要你写出一个比这个的时间复杂度、代码复杂度都要低的代码来,
    另外,我还要你求出有多少个数比它右边都要小,同时,从小到大输出他们的下标(从0开始)。

    Input

    第一行,是一个数T(T<=500),表示有多少组测试数据。
    
    第二行乃至结束,是T组数据,对于每组数据:
    第一行是一个数n(1<=n<=100000),表示这个数组的长度。
    第二行是n个整数,有空格分隔。

    Output

    对于每组数据,输出四行:
    第一行,一个数A,表示有多少个数比它左边都大
    第二行,A个整数,表示比它左边都大的数的下标
    第三行,一个数B,表示有多少个数比它右边都小
    第四行,B个整数,表示比它右边都小的数的下标
    请注意,那下标I,从左到右输出也就是从小到大
    

    Sample Input

    2
    4
    1 3 1 4
    5
    1 2 3 2 1

    Sample Output

    3
    0 1 3
    2
    2 3
    3
    0 1 2
    1
    4

    Hint

    数组太大要开成全局变量,即放在函数体外,因为定义在函数体内部是占用函数栈的空间的,而函数栈空间比较小,
    放里面很容易造成爆栈然后得到“运行时错误”的结果。
    另外,输入流和输出流是分开的,就是说,处理完一组数据,输出答案,再处理第二组数据,再输出第二组数据的答案,再处理第三组...,
    这样和处理完所有数据,再一次性输出,是完全等价的。并且,系统评判的题目都是这样,不需要保存所有答案一并输出。
    之所以这题是(二)滴原因是去年有道一的了喲,看看有助于解决题目哟亲~~~

    Source

    by lyd

    Provider

    admin

     

    #include<stdio.h>
    #include<string.h>
    int a[100000], b[100000];
    int main()
    {
        int m, n, sum, max, i;
        scanf("%d", &m);
        while(m--)
        {
            
            memset(a, 0, sizeof(a));
            memset(a, 0, sizeof(a));
            scanf("%d", &n);
            for(i=0; i<n; ++i)
            {
                scanf("%d", &a[i]);
                b[i] = a[i];
            }
            if(n == 1) {printf("1\n0\n1\n0\n"); continue;}
            max = a[0]; a[0] = 1; sum = 1;
            for(i=1; i<n; ++i)
            {
                if(a[i]>max)
                {
                    ++sum;
                    max = a[i];
                    a[i] = 1;
                }
                else a[i] = 0;
            }
            printf("%d\n0", sum);
            for(i=1; i<n; ++i)
            if(a[i]) printf(" %d", i);
            printf("\n");
            
            
            max = b[n-1]; b[n-1] = 0; sum = 1;
            for(i=n-2; i>=0; --i)
            {
                if(b[i]<max)
                {
                    ++sum;
                    max = b[i];
                    b[i] = 1;
                }
                else b[i] = 0;
            }
            printf("%d\n",sum);
            for(i=0; i<n-1; ++i)
            if(b[i]) printf("%d ", i);
            printf("%d\n", n-1);
            
        }
        return 0;
    }

    解题报告:
    博士生15分钟写出代码,而我发现这题我半小时不用就过了,而且是1AC,两个输出(判断左边的数都比它小和判断右边的数都比它小)其实是一样的,拿遍历左边的数都比它小的算法来说,第一个(即下标为0)的数必须输出的,将它设为最大的数,然后接着遍历(i++)遇到比MAX大的数a[i]先将此值赋予MAX然后将a[i]的值改为零,并且累加sum(多少个这样的数)否则a[i] = 0,直到i == n-1; 最后遍历输出值为1的a[i]的下标1,但注意:别忘了只输入一个值的时候,代码中有n-2时就应考虑到这点

  • 相关阅读:
    不用写代码的框架
    bat执行python脚本,执行多条命令
    VMware-workstation-full-15.1.0-13591040安装破解-附件密钥
    w10谷歌chrome关闭自动更新
    谷歌安装提示已经安装高版本解决
    python项目三方库导出导入 requirements.txt文件
    点阴影
    goto gamedev blog
    20135315-信息安全系统设计基础第五周学习总结
    win10 +python3.6环境下安装opencv以及pycharm导入cv2有问题的解决办法
  • 原文地址:https://www.cnblogs.com/liaoguifa/p/2763526.html
Copyright © 2020-2023  润新知