zoukankan      html  css  js  c++  java
  • 2016.7.12 NOIP2013提高组 day2解题报告(未完成版)

        考试马不停蹄地到来,昨天的程序还没改完,今天又考了day2,虽然没有昨天那么懵逼,但还是不尽如人意,现在还没讲题,我打算先自己看一次解题报告,争取加深理解,毕竟一位前辈说过,做一套题的质量取决于题本身的质量和你思考的深度。

    考试总结:

        1.数据分析推测可行算法很重要,要灵活掌握常用算法的时间复杂度;

        2.对拍的方式要熟练,写对拍耗费的时间过多;

        3.要加强代码实现的能力,比较突出的表现就是写200-300行多函数模拟或搜索的能力;

        4.不要急于写过不完的程序,要多拿一点时间来分析数据,样例不够还可以自己出(不然就会像今天一样写完了没事做;

        5.不要有畏难情绪,考试最重要的是思考而不是分数,只要花了足够的时间来思考,即使最后没实现,所获得的也远远比直接写暴力算法要多得多,现在练习最重要的还是思维,而且看似很难的题也有很多人做出来,所以一定不要害怕;

        6.要逐渐适应高强度长时间的思考,当然如果实在很累了还是可以去楼下买两串关东煮的xxx;

    参考资料:

        1.昨天的参考资料2;

        2.老师提供的解题报告3,来自DOVECL

     一.积木大赛

    题意:n是宽度,H是要求高度,求每一层的联通块;n<=100000;h<=10000;(题意理解有多么重要在这里就可见一斑了:我的理解让我局限于外层循环  maxnh,然而参考资料2的理解就打开了另一种算法:如何让一个空序列变成A序列; 

    题目分析:刚拿到这道题,maxnH*n的算法一定会浮现在我们的脑海里,接着,一些比较谨慎的人(毕竟虽然评测机理论速度能达到1e9,但由于分操作的存在,平时就算是一个很’干净’的1e8的程序评测时我们都会提心吊胆)会发现,最大1e9的计算量可能会超过时间;实际上也的确超了最后一组,所以采用更智能的方法是很有必要的;

        然后!一件神奇的事情发生了!我居然给内层用了分治(手动笑哭),然后费尽心思让它更复杂了(手动再见),唯一有安慰的是这样锻炼了一下我的思维能力orz,我觉得这个分治蛮巧妙的,所以顺便贴上来了:

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<queue>
    #include<set>
    using namespace std;
    int n,h[100005],ans,maxn;
    void res(int lef,int rig)
    {
        if(lef>=rig-1)
        {
            if(h[lef]>=1||h[rig]>=1)
               ans++;
               h[lef]--;
               if(lef!=rig)
               h[rig]--;
               return;
        }
        int mid=(lef+rig)/2;
        res(lef,mid);res(mid+1,rig);
        if(h[mid]>=0&&h[mid+1]>=0)ans--;
    }
    int main()
    {
        freopen("block.in","r",stdin);
        freopen("block.out","w",stdout);
        ios::sync_with_stdio(false);
        cin>>n;
        for(int i=1;i<=n;i++)
        {
        cin>>h[i];maxn=max(maxn,h[i]);
        }
        for(int i=1;i<=maxn;i++)
        {
            res(1,n);
        }
        cout<<ans;
        return 0;
    }

        然后这道题的正解应该是差分序列最快,然后也有同学用了分模块递归(用其他的数据结构应该是nlogn左右,这里也告诉我们一个道理:数据结构是基础,算法是方法,数据结构一定不能小瞧,要灵活掌握其基础上的运算!)

        因为差分序列比较经典(这是一种比较经典的数学思维运用,昨天的火柴也是)(简单证明:对于每个最小单调上升需要的搭建数为maxnh-minih),所以改了差分的程序(才不是因为这种比较简单呢qwqqq

        

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<queue>
    #include<set>
    using namespace std;
    int n,tot,h[100005];
    int main()
    {
        freopen("block.in","r",stdin);
        freopen("block.out","w",stdout);
        cin>>n;
        for(int i=1;i<=n;i++)
        cin>>h[i];
        tot=h[1];
        for(int i=2;i<=n;i++)
        {
            if(h[i]>h[i-1])//自动分模块
            tot+=h[i]-h[i-1];
        }
        cout<<tot;
        return 0;
    }

        这种题如果最开始不知道这种方法,对自己的方法没有信心的话可以用对拍验证(对拍一定要熟练,写对拍写20min未免得不偿失)。

    二.花匠

    题意:n花数,h高度,求正弦函数(误),求波动序列;n<=100000

    题目分析,把这道题初步分析了一下我就动手写了搜索+优化(过三组),事实证明这是多么愚蠢的决定......下次至少要给第二题半个小时的完全用来思考的时间,一般第二题的分是能拿满的。

        这道题一般的题解里有两种方法,一种是DP+数据结构(树状数组,线段树或排序树),时间复杂度为nlogn(外层n,内层线段树/树状数组操作logn),另一种是基于数据特点的找拐点,时间复杂度为n,然而!我们班有位大神!想出了O(n)的动态规划!(先膜拜两下)后两种方法都基于对数据的观察,所以说考试时观察数据实在是重要啊(当然,还有一种根据“没有条件会白给”原则的方法,选自参考资料,即因为数据随机分布,所以取区间500左右找最优决策点(最低点),全过。)

        为了锻炼一下自己,把O(n)的两种算法都写了一遍:

        线性动规:

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<queue>
    #include<set>
    using namespace std;
    const int MAXN=100005;
    int n,down_[MAXN],up_[MAXN],h[MAXN];
    int main()
    {
        freopen("flower.in","r",stdin);
        freopen("flower.out","w",stdout);
        ios::sync_with_stdio(false);
        cin>>n;
        for(int i=1;i<=n;i++)
        cin>>h[i];
        down_[1]=1;up_[1]=1;//不一定停于i点
        for(int i=2;i<=n;i++)
            if(h[i-1]==h[i])
            {
                up_[i]=up_[i-1];
                down_[i]=down_[i-1];
            }
            else if(h[i]>h[i-1])
            {
                up_[i]=max(up_[i-1],down_[i-1]+1);
                down_[i]=down_[i-1];
            }
            else
            {
                up_[i]=up_[i-1];
                down_[i]=max(down_[i-1],up_[i-1]+1);            
            }
        cout<<max(up_[n],down_[n]);
        return 0;
    }

    (真的是非常短写起来极其爽)(如果真的有人看我的冷门博客并且没看懂可以联系我的邮箱 SindarDawn@163.com)

        拐点版:(这个版本的理解需要一点思考)

        

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<queue>
    #include<set>
    using namespace std;
    int ans,h[100005],flg,n;
    int main()
    {
        freopen("flower.in","r",stdin);
        freopen("flower.out","w",stdout);
        cin>>n;
        for(int i=1;i<=n;i++)
        cin>>h[i];
        ans=1;flg=-1;//1:look for up;0:look for down
        for(int i=2;i<=n;i++)//1,2,whole,3
        {
            if(h[i]>h[i-1]&&flg)
            {
                ans++;flg=0;
            }
            else if(h[i]<h[i-1]&&(!flg||flg==-1))
            {
                ans++;flg=1;
            }
        }
        cout<<ans;
        return 0;
    }

    (好吧这个写起来更爽)

    三.华容道

    题意:n行m列,bx,by空白,fx,fy初始位置,dx,dy目标位置,q问题个数

        

        

             

  • 相关阅读:
    poplib
    【redis】哨兵模式
    no route to host
    修改文件失败,提示E509: 无法创建备份文件 (请加 ! 强制执行)
    【mysql】开启binlog后异常:impossible to write to binary log since BINLOG_FORMAT = STATEMENT
    rar
    manage.py命令
    zipfile
    【windows】git密码失效修改方式
    自动发现式推送数据,一次返回所有数据
  • 原文地址:https://www.cnblogs.com/SindarDawn/p/5664292.html
Copyright © 2011-2022 走看看