2019暑假集训8.24(problem2.baritone)(链表(巧妙数据结构))

Posted yyys-

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2019暑假集训8.24(problem2.baritone)(链表(巧妙数据结构))相关的知识,希望对你有一定的参考价值。

技术图片

数据结构好题!

因为思路是第一次见,所以就直接说思路。

题目抽象:

技术图片这是一个矩形

技术图片里面有很多的点,求至少覆盖k个点的矩形有多少个

 技术图片先确定上边界,下边界为低端

技术图片上边界下面的点用链表存起来

技术图片考虑以每个点作为左边界的贡献(线上的点也算在矩形内),假如k=3,那么右边界至少在橙色这根线这儿

技术图片符合要求的矩形的左边界范围L和右边界范围R如图

技术图片做出的贡献为L*R,如果前面还有点注意是左开右闭(因为右边到底都是可以的)

                                                                             然后移动左边界

技术图片到下一个点再计算贡献

技术图片再来移动下边界

技术图片一些点可能在同一水平线上,所以一开始可以用vector存起来,然后要删的点一个一个处理。现在考虑下边界移上去后删去一些点的影响

比如删去这个点

 技术图片(k=3),对于前面k-1个点和后面一个点会造成影响:前面k-1个点:删去后因为每次至少覆盖k个点,所以右边界要向右移动一个点;后面一个点:因为删去了前面的那个点,所以左边界要向左移动


 所以总的思路就是:枚举上边界,确定左边界和右边界,再移动下边界。

时间复杂度O(n^2 k)。上边界往下,下边界走到上边界,上边界n条,相当于图从上往下用线扫n次,每次链表中最多n个点,那么左边界最多有n条,每一条往后推k个点,n*n*k=n^2*k。

实现的细节在代码里有说,记得注意左开右闭以及删点影响的范围(画图看一下就明白了)。

技术图片
#include<bits/stdc++.h>
#define N 3021
#define LL long long
using namespace std;
int read()

    int x=0,f=1;char s=getchar();
    while(s<0||s>9)if(s==-)f=-1;s=getchar();
    while(s>=0&&s<=9)x=x*10+s-0;s=getchar();
    return x*f;

vector<int>belong[N];
struct point
    int x,y;
a[N*N];
LL val[N],id[N],pointx[N],pointy[N],nextt[N],pre[N],ord[N];
LL sum=0,ans=0,cnt=0,k,r,c,n;
bool cmp(const int &u,const int &v)

    if(pointy[u]==pointy[v])return pointx[u]<pointx[v];
    return pointy[u]<pointy[v];
 
void del(int d)

    nextt[pre[d]]=nextt[d];
    pre[nextt[d]]=pre[d];
    sum-=val[d];//以d为左边界的矩形要减去 
    int x=nextt[d],y=nextt[d];//对前k的点和后一个点作为左边界会有影响
    for(int i=1;i<k;++i)y=nextt[y];
    for(int i=1;i<=k;++i)
    
        int v=(pointy[x]-pointy[pre[x]])*(c-pointy[y]+1);//如果说两点在同一竖直线上则v=0,也满足要求 
        sum+=v-val[x];
        val[x]=v;
        x=pre[x];y=pre[y];
    

int idc;
int main()

    freopen("baritone.in","r",stdin);
    freopen("baritone.out","w",stdout);
    r=read(),c=read(),n=read();k=read();
    for(int i=1;i<=n;++i)
      a[i].x=read(),a[i].y=read(),belong[a[i].x].push_back(i);////保存这一行有那些点 
    for(int i=1;i<=r;++i)//枚举上边界 
    
        sum=0,cnt=0;//sum是全局变量,每一层下边界改变时会变化,每一个上边界对应一个sum 
        for(int j=0;j<=10;++j)//防止越界,k最大是10 
          pointy[++cnt]=0,pointy[++cnt]=c+1;
        for(int j=1;j<=n;++j)
          if(a[j].x>=i)//pointx 行坐标,pointy 纵坐标 
            pointy[++cnt]=a[j].y,pointx[cnt]=a[j].x,ord[j]=cnt;//ord[j]是第j个点在链表中的序号 
        for(int j=1;j<=cnt;++j)id[j]=j;
        sort(id+1,id+1+cnt,cmp);
        for(int j=1;j<cnt;++j)//前驱后继 
          nextt[id[j]]=id[j+1],pre[id[j+1]]=id[j];
        nextt[id[cnt]]=id[cnt];pre[id[1]]=id[1];
        for(int j=1;j<=cnt;++j)//枚举左边界
        
            int R=j;
            for(int p=1;p<k;++p) R=nextt[R];//R为右边界 
            val[j]=(pointy[j]-pointy[pre[j]])*(c-pointy[R]+1);//乘法原理 ,右边界一直到c都是满足的 
            sum+=val[j];//val上边界为i,下边界为r,左边界为j的矩形个数 
        
        for(int j=r;j>=i;--j)//枚举下边界
        
            ans+=sum;
            for(int p=0;p<(int)belong[j].size();++p)
              del(ord[belong[j][p]]);
         
    
    printf("%lld\\n",ans);
 
/*
2 2 1 1
1 2

3 2 3 3
1 1
3 1
2 2

3 2 3 2
1 1
3 1
2 2
*/
View Code

这道题还是很有价值的!??ヽ(°▽°)ノ?

以上是关于2019暑假集训8.24(problem2.baritone)(链表(巧妙数据结构))的主要内容,如果未能解决你的问题,请参考以下文章

2019暑假集训 8/16

杭电多校2019.7.24--暑假集训

2019暑假集训 8/2

2019暑假集训 数字游戏

2019暑假集训 Intervals

CSU-ACM2019暑假集训