zoukankan      html  css  js  c++  java
  • 【TMD模拟赛】上低音号 链表

    这道题一看有两个出发现点,一枚举点去找边界,想了一会就Pass了...,二是枚举相框,我们最起码枚举两个边界,然后发现平行边界更好处理,然而仍然只有30分,这个时候就来到了链表的神奇应用,我们枚举上界u,下界d在u的基础之上从下往上枚举,我们每次枚举上界的开始就把上界以下的点建成链表(它的形状大概是在从左到右的基础上对于同一列的从上倒下,就是蛇形),然后让下届去逼近并结算答案,十分巧妙。

    关于链表:大概有单向链表,双向链表,以及循环链表,他们作为数据结构的应用十分狭窄,只有在特定情境下才有大用处,所以在oi层面只有双向链表有一定用处,他的删除在记录位置的前提下是O(1)的,查询O(n),插入的话主要是找到合适的位置(前驱),剩下的就是O(1)了。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    typedef long long LL;
    const int N=3065;
    int pre[N],next[N],mem[N][N],last[N];
    int line,column,n,k;
    LL ans;
    bool ex[N];
    struct Point{int x,y;}p[N];
    inline bool comp(Point a,Point b){return a.y<b.y||(a.y==b.y&&a.x<b.x);}
    int main(){
      scanf("%d%d%d%d",&line,&column,&n,&k);
      for(int i=1;i<=n;++i)
        scanf("%d%d",&p[i].x,&p[i].y);
      std::sort(p+1,p+n+1,comp);
      for(int i=1;i<=n;++i)
        mem[p[i].x][++mem[p[i].x][0]]=i;
      for(int u=1;u<=n;++u){
        int pr=0;memset(ex,0,sizeof(ex));
        for(int i=u;i<=n;++i)
          for(int j=1;j<=mem[i][0];++j)
            ex[mem[i][j]]=true,last[mem[i][j]]=line;
        for(int i=1;i<=n;++i)
          if(ex[i])pre[i]=pr,next[pr]=i,pr=i;
        pre[n+1]=pr,next[pr]=n+1;
        for(int i=2;i<=k;++i)
          pre[n+i]=n+i-1,next[n+i-1]=n+i;
        for(int d=n;d>=u;--d){
          for(int i=1;i<=mem[d][0];++i){
            int nk=mem[d][i];
            for(int j=1;j<=k;++j)nk=next[nk];
            if(next[mem[d][i]]<=n&&p[next[mem[d][i]]].x!=d)
              ans+=(LL)(last[next[mem[d][i]]]-d+1)*
              (p[next[mem[d][i]]].y-p[pre[next[mem[d][i]]]].y)*
              (nk>n?0:column-p[nk].y+1),
              last[next[mem[d][i]]]=d-1;
            nk=pre[nk],
            ans+=(LL)(last[mem[d][i]]-d+1)*
            (p[mem[d][i]].y-p[pre[mem[d][i]]].y)*
            (nk>n?0:column-p[nk].y+1);
            for(int j=1,now=mem[d][i];j<k&&now;++j){
              now=pre[now],nk=pre[nk];
              if(now&&p[now].x!=d&&last[now]>=d)
                ans+=(LL)(last[now]-d+1)*
                (p[now].y-p[pre[now]].y)*
                (nk>n?0:column-p[nk].y+1),
                last[now]=d-1;
            }
          }
          for(int i=1;i<=mem[d][0];++i)
            next[pre[mem[d][i]]]=next[mem[d][i]],
            pre[next[mem[d][i]]]=pre[mem[d][i]];
        }
      }
      printf("%lld",ans);
    }
  • 相关阅读:
    Selenium2+python自动化17-JS处理滚动条
    图论一
    HDU1106
    银行家算法学习笔记
    NYOJ 540
    我在博客园 2013-08-02 22:04 200人阅读 评论(0) 收藏
    编程之美:平面最近点对
    RIA算法解决最小覆盖圆问题
    求两直线交点和三角形内外心
    求圆心
  • 原文地址:https://www.cnblogs.com/TSHugh/p/7617788.html
Copyright © 2011-2022 走看看