NOIP 信息学 奥赛 考纲 考点 模板 裸题 水题

NOIP 信息学 奥赛 考纲 考点 模板 裸题 水题

部分内容转自:http://blog.csdn.net/txl199106/article/details/71504478

 

NOIP知识点汇总

加*号是选学,加粗为重点,重要值排序不分先后

  • 基础算法

    • 贪心、枚举、分治、二分、倍增、*构造高精、模拟
  • 图论

    • 图 
      • 最短路(dijkstra、spfa、floyd),差分约束
      • 最小生成树(kruskal、prim)
      • 并查集(扩展域)
      • 拓扑排序
      • 二分图染色,*二分图匹配
      • tarjan找scc、桥、割点,缩点
      • *分数规划
    • 树 
      • 树上倍增(LCA)
      • 树的直径、树的重心
      • dfs序
      • *树链剖分
  • 数论

    • gcd、lcm
    • 埃氏筛法
    • exgcd,求解同余方程、逆元
    • 快速幂
    • *组合数学
    • 矩阵
  • 数据结构

    • 链表、队列(单调队列)、栈(单调栈)
    • 堆、st表、hash表
    • 线段树、树状数组
    • 字典树
    • *分块
  • 动态规划

    • 背包DP、树形DP、记忆化搜索、递推
    • 区间DP、序列DP
    • *DP优化(不涉及斜率优化、四边形不等式等等)
  • 搜索

    • 暴搜(dfs、bfs)
    • 搜索的剪枝
    • 启发式搜索(A*)
    • 迭代加深搜索、* IDA*
    • *随机化搜索
  • 其他算法

    • STL的基本使用方法
    • 脑洞的正确使用方法
    • *KMP
    • *状态压缩

 

省选知识点汇总

冲省选的,先把整理的NOIP知识点学扎实,注意一定要学扎实 
加粗是重点,星号是选学 
学无止境,欢迎大家继续补充~

  • 图论

    • 网络流(dinic,SAP,ISAP选一个,费用流写EK就行。*zkw费用流),二分图
    • 点分治,边分治,*动态点分治
    • 树链剖分,动态树,树分块
    • 虚树,*prufer编码
    • *仙人掌算法
  • 数据结构

    • 带权并查集
    • Splay(作为平衡树和维护区间),Treap,替罪羊树
    • 线段树(权值线段树),树状数组,*线段树合并
    • 分块,块状链表,*双向链表
    • 凸包
    • 树套树
    • 主席树,可持久化trie,*其它可持久化数据结构
    • 莫队算法,*树上莫队,CDQ分治,整体二分
    • 二维线段树,*KDtree
    • *舞蹈链,*二进制分组,*左偏树,*超哥线段树,*后缀平衡树,*fhqTreap
  • 字符串相关算法及数据结构

    • hash(自然溢出,双hash)
    • kmp,AC自动机,trie
    • 后缀数组
    • manacher,最小表示法
    • *后缀自动机,*回文自动机,*后缀树
  • 数学

    • 线性筛,积性函数,容斥原理,莫比乌斯反演
    • exgcd,费马小定理,Lucas定理,高中排列组合
    • 高斯消元,概率与期望相关
    • 中国剩余定理,BSGS,欧拉定理
    • 矩阵乘法
    • 单纯形法解线性规划
    • FFT
    • 线性代数(行列式)
    • *Simpson积分,高中求导与积分
    • *群论
    • *生成函数, 多项式类算法
    • 博弈论相关,*密码学,阶,原根
  • 计算几何

    • 向量的点积/叉积,计算几何基础
    • *二维计算几何相关,*三维计算几何相关
    • *半平面交,*旋转卡壳,*三角剖分
  • 搜索

    • A*,记忆化搜索,迭代深搜,双向广搜
    • 模拟退火,爬山算法,*随机增量法
  • 动态规划

    • 基础DP,树形DP,数位DP,状压DP,期望DP,基环树DP,*插头DP
    • 斜率优化,矩乘优化,单调队列优化,倍增优化,*四边形不等式优化
    • trie图DP,*仙人掌DP
  • 其他算法

    • 构造乱搞,随机化,三分法,打表启发式合并
    • Huffman树,2-sat,*朱刘算法

说真的,计算几何要么全场不会,要么全场AK。所以尽量花时间在别的地方吧。

以下是针对考点提供的裸题,例题,希望能加快读者理解掌握考点。2018-3-16 16:59

 

NOIP知识点汇总

加*号是选学,加粗为重点,重要值排序不分先后

  • 基础算法

    • 贪心、枚举、分治、二分、倍增、*构造高精、模拟
  • 图论

    • 图 
      • 最短路(dijkstra、spfa、floyd)
      • 差分约束
      • //P1645 序列
        //差分约束
        //样例通过,提交,测试点3,4,6WA
        //经过对比,发现,还是左边界的问题。
        //提交AC 2018-5-9
        #include <stdio.h>
        #include <string.h>
        struct node{
            int to,next,w;
        }e[1000+1000*2+100];
        int cnt=0,head[1100],d[1100],vis[1100],q[1100*10],R=-1999999999;
        int max(int a,int b){
            return a>b?a:b;
        }
        void add_edge(int u,int v,int w){
            cnt++,e[cnt].to=v,e[cnt].w=w,e[cnt].next=head[u],head[u]=cnt;//竟然漏了e[cnt].w=w;这句
        }
        void spfa(int x){
            int h,t,i,b,u,v,w;
            memset(vis,0,sizeof(vis));
            for(i=0;i<=R;i++)d[i]=-1999999999;
            h=t=1;
            q[t]=x,t++,vis[x]=1,d[x]=0;
            while(h<t){
                u=q[h],vis[u]=0,b=head[u];
                while(b){
                    v=e[b].to,w=e[b].w;
                    if(d[v]<d[u]+w){
                        d[v]=d[u]+w;
                        if(vis[v]==0){
                            vis[v]=1;
                            q[t]=v;
                            t++;
                        }
                    }
                    b=e[b].next;
                }
                h++;
            }
        }
        int main(){
            int u,v,w,i,n;
            memset(head,0,sizeof(head));
            scanf("%d",&n);
            for(i=1;i<=n;i++){
                scanf("%d%d%d",&u,&v,&w);
                R=max(R,v),add_edge(u-1,v,w);//此处写成 add_edge(u+1,v+1,w)
            }
            for(i=0;i<=R;i++)
                add_edge(i-1,i,0);
            for(i=0;i<=R;i++)
                add_edge(i,i-1,-1);
            spfa(0);
            printf("%d",d[R]);
            return 0;
        }
        试了:随机数据生成与对拍 但发现 该题数据 还想遵循一定规则,故随机数据生成 暂告 搁置 2018-5-10
         
      • 最小生成树(kruskal、prim)
      • 并查集(扩展域)
      • 拓扑排序
      • 二分图染色,*二分图匹配
      • tarjan找scc、桥、割点,缩点
      • *分数规划
    • 树 
      • 树上倍增(LCA):
      • http://blog.csdn.net/saramanda/article/details/54963914此文介绍得不错,可以作为初步了解,但又一个疑问,适用提交,满二叉树,完全二叉树,还是普通的二叉树。
      • https://www.cnblogs.com/yyf0309/p/5972701.html本人偏好此文,有图有程序。
      • 树的直径:
      • poj2631 求树的直径裸题
      • https://www.cnblogs.com/a-clown/p/6131346.html此文介绍得不错
      • http://poj.org/problem?id=2631可见该题
      • https://vjudge.net/problem/POJ-2631  可见该题
      • 带着问题学习,明显效率高了很多,https://www.cnblogs.com/jsawz/p/6809817.html该文有树的直径概念及代码 ,经样例模拟,发现此文树的直径代码有误,起始点疏漏了访问标记,造成多次访问。2018-3-21
      • 树上最长的简单路径即为树的直径。

        求树的直径的方法就是在树上任选一点u,求距离点u最远的点y,再求距离点y最远的点s,点y到点s的距离即为树的直径。

      • //poj 2631 Roads in the North
        //树的直径 裸题
        //该题没说道路的数量范围,采用C(n,2)
        //采用邻接表存储 数据
        //样例通过,提交AC 2018-3-18 20:27
        //1.树的直径
        //树上最长的简单路径即为树的直径。
        //求树的直径的方法就是在树上任选一点u,求距离点u最远的点y,再求距离点y最远的点s,点y到点s的距离即为树的直径。2018-3-21 AC
        #include <stdio.h>
        #include <string.h>
        int d[10100],head[10100],cnt=0,vis[10100];//没设置访问标志vis[10100],造成了理解困难
        struct node{
            int to,next,w;
        }e[10100*10100/2];
        int max(int a,int b){
            return a>b?a:b;
        }
        void add_edge(int u,int v,int w){
            cnt++,e[cnt].to=v,e[cnt].w=w,e[cnt].next=head[u],head[u]=cnt;
        }
        void dfs(int x){
            int v,b;
            b=head[x];
            while(b){
                v=e[b].to;
                if(!vis[v])d[v]=d[x]+e[b].w,vis[v]=1,dfs(v);//此处写成 if(!d[v])d[v]=d[x]+e[b].w,dfs(v);
                b=e[b].next;
            }
        }
        int main(){
            int u,v,w,n=0,y;
            memset(head,0,sizeof(head));
            while(scanf("%d%d%d",&u,&v,&w)!=EOF)n=max(max(u,v),n),add_edge(u,v,w),add_edge(v,u,w);//无向图
            memset(vis,0,sizeof(vis)),memset(d,0,sizeof(d));
            vis[1]=1,dfs(1);//注意vis[1]=1别忘了
            for(u=y=1;u<=n;u++)if(d[u]>d[y])y=u;
            memset(vis,0,sizeof(vis)),memset(d,0,sizeof(d));
            vis[y]=1,dfs(y);//注意vis[y]=1别忘了
            for(u=y=1;u<=n;u++)if(d[u]>d[y])y=u;
            printf("%d",d[y]);
            return 0;
        }
         
      • 树的重心
      • http://blog.csdn.net/acdreamers/article/details/16905653此文介绍得不错
      • https://www.cnblogs.com/jsawz/p/6809817.html此文介绍了树的重心概念
      • 若有一点,其所有子树中最大子树的节点数最少,则该点就是这棵树的重心。

        一般的树只有一个重心,有些有偶数个节点的树,有两个节点。

        求树的重心方法就是随意确定一个根节点,先把无根树转化为有根树,dfs求出所有点的子树的节点个数。如果有一点满足该点的子树的节点数的二倍大于等于总结点数(size[u]*2>=n),并且该点的儿子都满足子树的节点数的二倍小于等于总结点数(size[son_u]*2<=n),这个点就是树的重心。

      • poj 1655 Balancing Act
      • https://vjudge.net/problem/POJ-1655可见该题
      • https://www.cnblogs.com/kuangbin/p/3427267.html此文代码写得不错
      • http://blog.csdn.net/bigbigship/article/details/47261031此文代码也写得不错
      • //poj-1655
        //样例通过,提交AC 2018-3-21 17:34
        #include <stdio.h>
        #include <string.h>
        #define maxn 20100
        int son[maxn],cnt,head[maxn],vis[maxn],num,n,ans;//此处写成 head[maxn]
        struct node{
            int to,next;
        }e[maxn*2];//此处写成 e[maxn*maxn/2]
        void add_edge(int u,int v){//邻接表
            cnt++,e[cnt].to=v,e[cnt].next=head[u],head[u]=cnt;
        }
        int max(int a,int b){
            return a>b?a:b;
        }
        void dfs(int x){
            int b,v,maxson=0;//maxson是临时变量,而非全局变量
            son[x]=1,b=head[x];
            while(b){
                v=e[b].to;
                if(!vis[v])vis[v]=1,dfs(v),son[x]+=son[v];
                maxson=max(maxson,son[v]);
                b=e[b].next;
            }
            maxson=max(maxson,n-son[x]);//此处写成maxson=max(maxson,n-maxson);//最大子树节点数
            if(maxson<num||maxson==num&&ans>x)num=maxson,ans=x;
        }
        int main(){
            int T,i,u,v;
            scanf("%d",&T);
            while(T--){
                memset(head,0,sizeof(head)),memset(vis,0,sizeof(vis)),num=999999999,n,ans=999999999,cnt=0;//漏了cnt=0一直Runtime Error//注意,每次num=999999999,n,ans=999999999都要初始化
                scanf("%d",&n);
                for(i=1;i<=n-1;i++)scanf("%d%d",&u,&v),add_edge(u,v),add_edge(v,u);//无向图
                vis[1]=1,dfs(1);
                printf("%d %d\n",ans,num);//此处写在while循环之外,真是昏招
            }
            return 0;
        }

         
      • dfs序
      • *树链剖分
  • 数论

    • gcd、lcm
    • 埃氏筛法
    • exgcd,
    • //P1516 青蛙的约会
    • //https://www.luogu.org/problemnew/show/P1516可提交测评
      //0 < L < =2100000000已经接近int的极限,该题考虑用long long
      //一段时间的数论学习下来,还是小有成就的,理解力,推导能力大幅度的上了一个台阶,读者若想好好学习,可参看笔者文章
      //https://blog.csdn.net/mrcrack/article/details/80352151
      //以下为AC代码,一次编写成功。2018-6-18 18:59
      #include <stdio.h>
      #define LL long long
      LL gcd(LL a,LL b){
          return b?gcd(b,a%b):a;
      }
      LL exgcd(LL a,LL b,LL *x,LL *y){
          LL t,d;
          if(b==0){
              *x=1,*y=0;
              return a;
          }
          d=exgcd(b,a%b,x,y);
          t=*x,*x=*y,*y=t-a/b**y;
          return d;
      }
      int main(){
          LL X,Y,M,N,L;
          LL a,b,c,d;
          LL a0,b0,c0;
          LL x0,y0,x1;
          scanf("%lld%lld%lld%lld%lld",&X,&Y,&M,&N,&L);
          a=((N-M)%L+L)%L,b=L,c=((X-Y)%L+L)%L;
          d=gcd(a,b);
          if(c%d){
              printf("Impossible");
              return 0;
          }
          a0=a/d,b0=b/d,c0=c/d;
          exgcd(a0,b0,&x0,&y0);
          x0*=c0,y0*=c0;
          x1=(x0%b0+b0)%b0;
          printf("%lld",x1);
          return 0;
      }


       
    • //p1516 青蛙的约会
      //https://www.luogu.org/problemnew/show/P1516可提交测评
      //扩展欧几里得算法
      //是否需要考虑,正负数?
      //该题,比较简单的就是,输出Impossible,猜测能拿到20分
      //考虑了,还是采用long long比int胜算大
      //以下为运用了 求解线性同余方程 性质,何时有解,何时无解,提交20分,计算过程中没有顾及负数。满意2018-5-16
      //样例通过,提交AC 2018-5-16 17:30 以下为AC 代码
      #include <stdio.h>
      #define LL long long
      LL X,Y,M,N,L,a,b,c;
      LL gcd(LL a,LL b){
          return b?gcd(b,a%b):a;
      }
      LL exgcd(LL a,LL b,LL *x,LL *y){
          LL t,d;
          if(b==0){
              *x=1,*y=0;//此处写成 *x=c/a
              return a;
          }
          d=exgcd(b,a%b,x,y);
          t=*x,*x=*y,*y=t-a/b**y;
          return d;
      }
      int main(){
          LL x,y,t,d;
          scanf("%lld%lld%lld%lld%lld",&X,&Y,&M,&N,&L);
          a=((N-M)%L+L)%L,b=L,c=((X-Y)%L+L)%L;//此处写成 a=N-M,b=L,c=X-Y;
          if(c%gcd(a,b)){
              printf("Impossible");
              return 0;
          }
          d=exgcd(a,b,&x,&y);
          t=b/d;
          x=(c/d*x%t+t)%t;//此处写成 x=(c*x%t+t)%t; 只有50分 ,修改,只有70分
          printf("%lld",x);
          return 0;
      }


       
    • //p1516 青蛙的约会
      //https://www.luogu.org/problemnew/show/P1516可提交测评
      //扩展欧几里得算法
      //是否需要考虑,正负数?
      //该题,比较简单的就是,输出Impossible,猜测能拿到20分
      //考虑了,还是采用long long比int胜算大
      //以下为运用了 求解线性同余方程 性质,何时有解,何时无解,提交20分,计算过程中没有顾及负数。满意2018-5-16 
      #include <stdio.h>
      #define LL long long
      LL X,Y,M,N,L,a,b,c;
      LL gcd(LL a,LL b){
          return b?gcd(b,a%b):a;
      }
      int main(){
          scanf("%lld%lld%lld%lld%lld",&X,&Y,&M,&N,&L);
          a=M-N,b=L,c=Y-X;
          if(c%gcd(a,b)){
              printf("Impossible");
              return 0;
          }
          return 0;
      }
    • //p1516 青蛙的约会
      //https://www.luogu.org/problemnew/show/P1516可提交测评 
      //扩展欧几里得算法
      //是否需要考虑,正负数?
      //该题,比较简单的就是,输出Impossible,猜测能拿到20分
      //考虑了,还是采用long long比int胜算大
      //以下为20分代码,满意 2018-5-16
      #include <stdio.h>
      int main(){
          printf("Impossible");
          return 0;
    • 求解同余方程、逆元
    • 快速幂
    • *组合数学
    • 矩阵
  • 数据结构

    • 链表、
    • 队列(单调队列)、
    • //P1886 滑动窗口
      //在线测评地址https://www.luogu.org/problemnew/show/P1886
      //先纯模拟,O(n^2),估计最多得10分,样例很快通过,提交
      //测试点8-10 TLE,还是那句话,数据太水了。2018-12-25
      #include <stdio.h>
      #define maxn 1000100
      int a[maxn],b[maxn],c[maxn],b_min,c_max;//b最小值c[最大值
      int min(int a,int b){
          return a<b?a:b;
      }
      int max(int a,int b){
          return a>b?a:b;
      }
      int main(){
          int n,k,i,j,cnt=0;
          scanf("%d%d",&n,&k);
          for(i=1;i<=n;i++)
              scanf("%d",&a[i]);
          for(i=1;i<=n-k+1;i++){
              b_min=c_max=a[i];
              for(j=i;j<=i+k-1;j++){
                  b_min=min(b_min,a[j]);
                  c_max=max(c_max,a[j]);
              }
              cnt++,b[cnt]=b_min,c[cnt]=c_max;    
          }
          for(i=1;i<=cnt;i++)
              printf("%d ",b[i]);
          printf("\n");
          for(i=1;i<=cnt;i++)        
              printf("%d ",c[i]);
          return 0;
      }

    • //P1886 滑动窗口
      //在线测评地址https://www.luogu.org/problemnew/show/P1886
      //AC。2018-12-25
      #include <stdio.h>
      #include <string.h>
      #define maxn 1000100
      int q[maxn],a[maxn];//存储序列
      int main(){
          int n,k,i,h,t;
          scanf("%d%d",&n,&k);
          for(i=1;i<=n;i++)scanf("%d",&a[i]);
          h=t=1,q[t]=1,t++;//此处写成 q[t]=a[1]
          for(i=1;i<=n;i++){//此处写成 for(i=1;i<=n-k+1;i++)
              while(h<t&&a[q[t-1]]>=a[i])t--;//插入队列
              q[t]=i,t++;
              while(h<t&&q[h]+k-1<i)h++;//清理队列
              if(i>=k)//漏了此句
                  printf("%d ",a[q[h]]);
          }
          printf("\n");
          h=t=1,q[t]=1,t++;//此处写成 q[t]=a[1]
          for(i=1;i<=n;i++){//存最大值
              while(h<t&&a[q[t-1]]<=a[i])t--;
              q[t]=i,t++;
              while(h<t&&q[h]+k-1<i)h++;
              if(i>=k)printf("%d ",a[q[h]]);
          }
          return 0;
      }

    • P1886 滑动窗口
    • https://www.luogu.org/problemnew/show/P1886
    • //P1886 滑动窗口
      //https://www.luogu.org/problemnew/show/P1886可见该题
      //https://vjudge.net/problem/POJ-2823可见该题
      //读题发现看不懂,仔细看了题中的模拟过程,还是看懂了
      //读题,发现该题可以模拟出来,但是会超时
      //50%的数据,n<=10^5 100%的数据,n<=10^6
      //可以预测 模拟 大约30分
      //用模拟代码提交,只有测试点9 TLE 不敢想象啊 2018-3-23
    • //P1886 滑动窗口
      //提交,测试点1-8,10WA
      //仔细一看,样例都没通过,确实看走眼了
      //样例通过,提交AC 2018-3-23 21:20
      #include <stdio.h>
      #define maxn 1000100
      int a[maxn],q[maxn],h,t;
      int main(){
          int i,j,n,k;
          scanf("%d%d",&n,&k);
          for(i=1;i<=n;i++)scanf("%d",&a[i]);
          h=t=1;
          for(i=1;i<=n;i++){//最小值
              while(h<t&&a[q[t-1]]>a[i])t--;
              q[t]=i,t++;
              while(h<t&&q[h]+k-1<i)h++;//此处写成 while(h<t&&q[h]+k<i)h++;
              if(i>=k)printf("%d ",a[q[h]]);
          }
          printf("\n"),h=t=1;
          for(i=1;i<=n;i++){//最大值
              while(h<t&&a[q[t-1]]<a[i])t--;
              q[t]=i,t++;
              while(h<t&&q[h]+k-1<i)h++;
              if(i>=k)printf("%d ",a[q[h]]);
          }
          return 0;
      }
      以下代码为90分 纯枚举算法
       
    • //此文代码写得不错https://www.cnblogs.com/wawcac-blog/p/6986710.html
      #include <stdio.h>
      #define maxn 1000100
      #define INF 999999999
      int a[maxn],min[maxn],max[maxn];
      int main(){
          int n,k,i,j,b,c;//b最小 c最大
          scanf("%d%d",&n,&k);
          for(i=1;i<=n;i++)scanf("%d",&a[i]);
          for(i=1;i<=n-k+1;i++){
              b=INF,c=-INF;
              for(j=i;j<=i+k-1;j++){
                  if(a[j]<b)b=a[j];
                  if(a[j]>c)c=a[j];
              }
              min[i]=b,max[i]=c;
          }
          for(i=1;i<=n-k+1;i++)printf("%d ",min[i]);
          printf("\n");
          for(i=1;i<=n-k+1;i++)printf("%d ",max[i]);    
          return 0;
      }
    • //hdu 3530 Subsequence
      //https://vjudge.net/problem/HDU-3530可见该题
      //单调队列
      //看了半天题目,竟然没看懂,看了中文题目,才发现the difference between指的是 差值 而不是 不同
      //弄明白题意,开始考虑该题思路
      //https://blog.csdn.net/zxf654073270/article/details/42712351此文代码写得不错
      //https://blog.csdn.net/dan__ge/article/details/51746590此文代码也写得不错
      //提交,Compilation Error,发现要将中文注释删除,将中文注释全部删除后,提交AC 2018-3-24
      //故下面代码要想AC,需将中文注释全部删除.
      #include <stdio.h>
      #define maxn 100100
      int a[maxn],q1[maxn],q2[maxn],h1,t1,h2,t2,pos;
      int max(int a,int b){
          return a>b?a:b;
      }
      int main(){
          int n,m,k,i,ans;
          while(scanf("%d%d%d",&n,&m,&k)!=EOF){
              h1=t1=1,h2=t2=1,pos=0,ans=0;
              for(i=1;i<=n;i++)scanf("%d",&a[i]);
              for(i=1;i<=n;i++){
                  while(h1<t1&&a[q1[t1-1]]>a[i])t1--;
                  while(h2<t2&&a[q2[t2-1]]<a[i])t2--;
                  q1[t1++]=i,q2[t2++]=i;
                  while(h1<t1&&h2<t2&&a[q2[h2]]-a[q1[h1]]>k)
                      if(q1[h1]<q2[h2])pos=q1[h1++];
                      else pos=q2[h2++];
                  if(h1<t1&&h2<t2&&a[q2[h2]]-a[q1[h1]]>=m)ans=max(ans,i-pos);
              }
              printf("%d\n",ans);
          }
          return 0;
      }

      以下代码包含中文注释,无法AC,仅供参考之用
    • #include <stdio.h>
      #define maxn 100100
      int a[maxn],q1[maxn],q2[maxn],h1,t1,h2,t2,pos;
      int max(int a,int b){
          return a>b?a:b;
      }
      int main(){
          int n,m,k,i,ans;
          while(scanf("%d%d%d",&n,&m,&k)!=EOF){
              h1=t1=1,h2=t2=1,pos=0,ans=0;//请注意pos初始化很重要,pos=0而非1
              for(i=1;i<=n;i++)scanf("%d",&a[i]);
              for(i=1;i<=n;i++){
                  while(h1<t1&&a[q1[t1-1]]>a[i])t1--;//最小值 由小到大 队列
                  while(h2<t2&&a[q2[t2-1]]<a[i])t2--;//最大值 由大到小 队列
                  q1[t1++]=i,q2[t2++]=i;
                  while(h1<t1&&h2<t2&&a[q2[h2]]-a[q1[h1]]>k)
                      if(q1[h1]<q2[h2])pos=q1[h1++];
                      else pos=q2[h2++];
                  if(h1<t1&&h2<t2&&a[q2[h2]]-a[q1[h1]]>=m)ans=max(ans,i-pos);//此处写成 if(h1<t1&&h2<t2&&q2[h2]-q1[h1]<=m)ans=max(ans,i-pos);真是昏招啊
              }
              printf("%d\n",ans);
          }
          return 0;
      }

       
    • 栈(单调栈)
    • //P2866 [USACO06NOV]糟糕的一天Bad Hair Day
      //在线测评地址https://www.luogu.org/problemnew/show/P2866 
      //先试试纯模拟O(n^2) 
      //(8000+0)*8000/2=6.4*10^9
      //个数要采用long long
      //样例通过,提交,测试点2,8,10TLE 70分,还算满意,同时说明数据挺水。
      //2018-12-26 20:43 
      #include <stdio.h>
      #define LL long long
      LL cnt=0;
      int h[80100];
      int main(){
          int n,i,j;
          scanf("%d",&n);
          for(i=1;i<=n;i++)scanf("%d",&h[i]);
          for(i=1;i<=n;i++)
              for(j=i+1;j<=n;j++)
                  if(h[i]>h[j])cnt++;
                  else break;
          printf("%lld\n",cnt);
          return 0;
      }

    • //P2866 [USACO06NOV]糟糕的一天Bad Hair Day
      //在线测评地址https://www.luogu.org/problemnew/show/P2866 
      //先试试纯模拟O(n^2) 
      //(8000+0)*8000/2=6.4*10^9
      //个数要采用long long
      //样例通过,提交,测试点2,8,10TLE 70分,还算满意,同时说明数据挺水。
      //2018-12-26 20:43
      //开一个栈,a[i]元素必需置于栈顶,放入之前,top的数值,表示a[i]能被之前的几头牛看见。 
      //样例通过,提交AC。2018-21-26 21:00 
      #include <stdio.h>
      #define LL long long
      LL cnt=0;
      int h[80100],stack[80100],top=0;
      int main(){
          int n,i;
          scanf("%d",&n);
          for(i=1;i<=n;i++){
              scanf("%d",&h[i]);
              while(top>0&&stack[top]<=h[i])top--;//弹出不能看见a[i]的牛
              cnt+=top;
              stack[++top]=h[i]; 
          }
          printf("%lld\n",cnt);
          return 0;
      }

       

    • //poj 3250 Bad Hair Day
      //https://vjudge.net/problem/POJ-3250可见该题
      //首先采用纯模拟
      //程序编写比较容易,提交也出现了意料中的Time Limit Exceeded
      //这种情况比较常见,需要学习特定算法,单调栈
      //https://blog.csdn.net/alongela/article/details/8229702该文思路介绍得不错,思路摘抄如下:
      //从左到右依次读取当前牛的高度,从栈顶开始把高度小于或等于当前牛的高度的那些元素删除,此时栈中剩下的元素的数量就是可以看见当前牛的其他牛的数量。把这个数量加在一起,就可以得到最后的答案了。
      //仔细想想,这个思路,不通过专门训练,很难想到
      //样例通过,提交Wrong Answer
      //仔细思考,(80000+0)/2*80000=32*10^8=3.2*10^9 int要溢出,果断改成long long
      //提交Wrong Answer
      //无奈,https://www.luogu.org/problemnew/show/P2866提交,竟然AC ,没想法啊
      //http://codevs.cn/problem/3098/提交,还是AC
      //https://vjudge.net/problem/POJ-3250提交,AC,真是奇怪了,代码没改过啊!2018-3-26 20:56
      //调出提交的代码,才发现,测试语句未删除,确实有误。2018-3-26 21:00
      #include <stdio.h>
      #define maxn 80100
      int a[maxn],n,stack[maxn],top=0;
      long long cnt=0;
      int main(){
          int i;
          scanf("%d",&n);
          for(i=1;i<=n;i++){
              scanf("%d",&a[i]);
              while(top>0&&stack[top]<=a[i])top--;//此处写成 while(top>0&&stack[top]<a[i])top--;
              cnt+=top;
              stack[++top]=a[i];
          }
          printf("%lld",cnt);
          return 0;
      }


       
    • 堆、
    • st表、
    • //P3865 【模板】ST表
      //https://www.cnblogs.com/Blackops/p/6295094.html此文思路介绍得不错
      //样例通过,提交AC 2018-4-11 16:31
      #include <stdio.h>
      int f[100100][25],n,m,a[100100];
      int max(int a,int b){
          return a>b?a:b;
      }
      int main(){
          int i,j,left,right,k;
          scanf("%d%d",&n,&m);
          for(i=1;i<=n;i++)scanf("%d",&a[i]),f[i][0]=a[i];
          for(j=1;(1<<j)<=n;j++)//此处写成 for(j=1;j<=n;j++)
              for(i=1;i+(1<<j)-1<=n;i++)//此处写成 for(i=1;i<=n;i++)
                  f[i][j]=max(f[i][j-1],f[i+(1<<j-1)][j-1]);//此处写成 f[i][j]=max(f[i][j-1],f[i+(1<<j-1)-1][j-1]);
          while(m--){
              scanf("%d%d",&left,&right),k=0;
              while(1<<k+1<right-left+2)k++;//计算 left+2^k-1<right-(1<<k)+1
              printf("%d\n",max(f[left][k],f[right-(1<<k)+1][k]));
          }
          return 0;
      }

      //P2251 质量检测
      //st表
      //样例通过,提交,全WA
      //排查,发现将right=m写成了right=4
      //修改,提交AC 2018-4-12
      #include <stdio.h>
      #define maxn 100100
      int f[maxn][25],a[maxn];
      int min(int a,int b){
          return a<b?a:b;
      }
      int main(){
          int n,m,i,j,left,right,k;
          scanf("%d%d",&n,&m);
          for(i=1;i<=n;i++)scanf("%d",&a[i]),f[i][0]=a[i];
          for(j=1;(1<<j-1)<=n;j++)
              for(i=1;i+(1<<j-1)<=n;i++)
                  f[i][j]=min(f[i][j-1],f[i+(1<<j-1)][j-1]);
          for(left=1,right=m;right<=n;i++){//此处写成 for(left=1,right=4;right<=n;i++) 昏招
              k=0;
              while((1<<k+1)<right-left+2)k++;
              printf("%d\n",min(f[left][k],f[right-(1<<k)+1][k]));
              left++,right++;
          }
          return 0;
      }


       
    • hash表(哈希表)
    • 水题 hdu 1128 Self Numbers
    • https://vjudge.net/problem/HDU-1128可见该题
    • https://blog.csdn.net/laojiu_/article/details/51169445此文代码写得不错
    • //hdu 1128 Self Numbers
      //看了数据范围less than or equal 1000000至少得采用O(n)算法
      //https://blog.csdn.net/laojiu_/article/details/51169445此文代码写得不错
      //样例通过,提交AC 2018-3-28 17:20
      #include <stdio.h>
      #include <string.h>
      #define maxn 1000100
      int hash[maxn];
      int fun(int x){
          int sum=0;
          while(x)sum+=x%10,x/=10;
          return sum;
      }
      int main(){
          int i,t;
          memset(hash,0,sizeof(hash));
          for(i=1;i<=maxn;i++)t=i,t+=fun(i),hash[t]=1;
          for(i=1;i<=maxn-100;i++)
              if(!hash[i])
                  printf("%d\n",i);
          return 0;
      }
    • //hdu 1014 Uniform Generator
      //https://vjudge.net/problem/HDU-1014可见该题
      //哈希表水题
      //结合文中例子,看懂该题。
      //一直在犹豫,算几次才算结束,
      //https://blog.csdn.net/laojiu_/article/details/51165229翻看代码,发现上述问题解决
      //总结,多模拟,大胆猜想。
      //样例通过,提交AC 2018-3-29
      #include <stdio.h>
      #include <string.h>
      int hash[100100];
      int main(){
          int step,mod,i,x;
          while(scanf("%d%d",&step,&mod)!=EOF){
              memset(hash,0,sizeof(hash)),x=0;
              for(i=1;i<=mod;i++){
                  x=(x+step)%mod;
                  if(!hash[x])hash[x]=1;
                  else break;
              }
              if(i==mod+1)printf("%10d%10d    Good Choice\n\n",step,mod);
              else printf("%10d%10d    Bad Choice\n\n",step,mod);
          }
          return 0;
      }  



       
    • 线段树、
    • //https://www.luogu.org/problemnew/show/P3372
    • //洛谷 P3372 【模板】线段树 1
      //调了会,样例通过,提交AC 2018-5-8 收获是 对 线段树 理解更深刻了
      #include <stdio.h>
      #include <string.h>
      #define maxn 100100
      #define LL long long
      LL n,m,lazy[4*maxn],ans,max_k=-999999999;
      struct node{
          LL left,right,v;
      }q[4*maxn];
      void build(LL k,LL left,LL right){
          LL mid=(left+right)/2;
          q[k].left=left,q[k].right=right;
          if(q[k].left==q[k].right){
              scanf("%lld",&q[k].v);
              if(max_k<k)max_k=k;//判断最大节点位置
              return ;
          }
          build(2*k,left,mid);
          build(2*k+1,mid+1,right);
          q[k].v=q[2*k].v+q[2*k+1].v;
      }
      void down(LL k){
          LL v=lazy[k];
          //此处多写了此句q[k].v+=(q[k].right-q[k].left+1)*v;
          if(2*k<=max_k){//判断有无越界
              lazy[2*k]+=v;
              q[2*k].v+=(q[2*k].right-q[2*k].left+1)*v;//漏了此句
          }
          if(2*k+1<=max_k){//判断有无越界
              lazy[2*k+1]+=v;
              q[2*k+1].v+=(q[2*k+1].right-q[2*k+1].left+1)*v;//漏了此句
          }
          lazy[k]=0;
      }
      void query(LL k,LL left,LL right){
          LL mid=(q[k].left+q[k].right)/2;//此处写成 LL mid=(left+right)/2;
          if(left<=q[k].left&&q[k].right<=right){
              ans+=q[k].v;
              return ;
          }
          if(lazy[k])down(k);
          if(left<=mid)query(2*k,left,right);
          if(right>=mid+1)query(2*k+1,left,right);
      }
      void add(LL k,LL left,LL right,LL v){
          LL mid=(q[k].left+q[k].right)/2;//此处写成 LL mid=(left+right)/2;
          if(left<=q[k].left&&q[k].right<=right){
              q[k].v+=(q[k].right-q[k].left+1)*v;
              lazy[k]+=v;//漏了此句
              return ;
          }
          if(lazy[k])down(k);
          if(left<=mid)add(2*k,left,right,v);//此处写成 query(2*k,left,right)昏招
          if(right>=mid+1)add(2*k+1,left,right,v);//此处写成 query(2*k+1,left,right)昏招
          q[k].v=q[2*k].v+q[2*k+1].v;
      }
      int main(){
          LL i,cmd,x,y,v;
          scanf("%lld%lld",&n,&m);
          build(1,1,n);
          memset(lazy,0,sizeof(lazy));
          while(m--){
              scanf("%lld",&cmd);
              if(cmd==2){
                  ans=0;
                  scanf("%lld%lld",&x,&y);
                  query(1,x,y);
                  printf("%lld\n",ans);
              }else{//cmd==1
                  scanf("%lld%lld%lld",&x,&y,&v);
                  add(1,x,y,v);
              }
          }
          return 0;
      }

      //P3372 【模板】线段树 1
      //枚举的方式,猜测70分。
      //果然,提交70分,测试点8,9,10 TLE 2018-5-7 18:01
      #include <stdio.h>
      #define maxn 100100
      #define LL long long
      LL a[maxn];
      int main(){
          LL n,m,i,j,cmd,x,y,k,sum;
          scanf("%lld%lld",&n,&m);
          for(i=1;i<=n;i++)scanf("%lld",&a[i]);
          while(m--){
              scanf("%lld",&cmd);
              if(cmd==1){
                  scanf("%lld%lld%lld",&x,&y,&k);
                  for(i=x;i<=y;i++)a[i]+=k;
              }else{
                  sum=0;
                  scanf("%lld%lld",&x,&y);
                  for(i=x;i<=y;i++)sum+=a[i];
                  printf("%lld\n",sum);
              }
          }
          return 0;
      }

       
    • 树状数组
    • 字典树
    • *分块
  • 动态规划

  • 连续最大子段和
  • //P1115 最大子段和

  • //https://www.luogu.org/problemnew/show/P1115可提交测评
    //f[i]表示以a[i]结尾的最大子段和
    //样例通过,提交AC 2018-4-24 20:38
    #include <stdio.h>
    #define maxn 200100
    int a[maxn],f[maxn],MAX;
    int max(int a,int b){
        return a>b?a:b;
    }
    int main(){
        int i,n;
        scanf("%d",&n);
        for(i=1;i<=n;i++)scanf("%d",&a[i]);
        MAX=f[1]=a[1];
        for(i=2;i<=n;i++){//算法的时间复杂度O(n)
            f[i]=max(f[i-1]+a[i],a[i]);
            MAX=max(MAX,f[i]);
        }
        printf("%d",MAX);
        return 0;
    }

     

    • 背包DP、树形DP、记忆化搜索、递推
    • 区间DP、序列DP
    • *DP优化(不涉及斜率优化、四边形不等式等等)
  • 搜索

    • 暴搜(dfs、bfs)
    • 搜索的剪枝
    • 启发式搜索(A*)
    • 迭代加深搜索、* IDA*
    • *随机化搜索
  • 其他算法

    • STL的基本使用方法
    • 脑洞的正确使用方法
    • *KMP
    • *状态压缩

 

省选知识点汇总

冲省选的,先把整理的NOIP知识点学扎实,注意一定要学扎实 
加粗是重点,星号是选学 
学无止境,欢迎大家继续补充~

  • 图论

    • 网络流(dinic,SAP,ISAP选一个,费用流写EK就行。*zkw费用流),二分图
    • 点分治,边分治,*动态点分治
    • 树链剖分,动态树,树分块
    • 虚树,*prufer编码
    • *仙人掌算法
  • 数据结构

    • 带权并查集
    • Splay(作为平衡树和维护区间),Treap,替罪羊树
    • 线段树(权值线段树),树状数组,*线段树合并
    • 分块,块状链表,*双向链表
    • 凸包
    • 树套树
    • 主席树,可持久化trie,*其它可持久化数据结构
    • 莫队算法,*树上莫队,CDQ分治,整体二分
    • 二维线段树,*KDtree
    • *舞蹈链,*二进制分组,*左偏树,*超哥线段树,*后缀平衡树,*fhqTreap
  • 字符串相关算法及数据结构

    • hash(自然溢出,双hash)
    • kmp,AC自动机,trie
    • 后缀数组
    • manacher,最小表示法
    • *后缀自动机,*回文自动机,*后缀树
  • 数学

    • 线性筛,积性函数,容斥原理,莫比乌斯反演
    • exgcd,费马小定理,Lucas定理,高中排列组合
    • 高斯消元,概率与期望相关
    • 中国剩余定理,BSGS,欧拉定理
    • 矩阵乘法
    • 单纯形法解线性规划
    • FFT
    • 线性代数(行列式)
    • *Simpson积分,高中求导与积分
    • *群论
    • *生成函数, 多项式类算法
    • 博弈论相关,*密码学,阶,原根
  • 计算几何

    • 向量的点积/叉积,计算几何基础
    • *二维计算几何相关,*三维计算几何相关
    • *半平面交,*旋转卡壳,*三角剖分
  • 搜索

    • A*,记忆化搜索,迭代深搜,双向广搜
    • 模拟退火,爬山算法,*随机增量法
  • 动态规划

    • 基础DP,树形DP,数位DP,状压DP,期望DP,基环树DP,*插头DP
    • 斜率优化,矩乘优化,单调队列优化,倍增优化,*四边形不等式优化
    • trie图DP,*仙人掌DP
  • 其他算法

    • 构造乱搞,随机化,三分法,打表启发式合并
    • Huffman树,2-sat,*朱刘算法

说真的,计算几何要么全场不会,要么全场AK。所以尽量花时间在别的地方吧。

 

 

 

 

 

 

 

  • 7
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值