【刷题】Grab the Seat!

题目地址:C-Grab the Seat!_"蔚来杯"2022牛客暑期多校训练营1 (nowcoder.com)

题目类型:涉及几何的枚举优化

题目思路:

//涉及几何的枚举优化
//直接在x-y坐标系下画图理解

//先判断连线后,每个人能够挡住的范围是哪一块
//每一列,第二个人必被第一个人挡住,以此类推

//问题简化为:求每一列 没有被挡住的最后一个人
//且,可以将每个人能挡住的右边三角形,作水平辅助线,拆分成右上方三角形和右下方三角形

//对于右上角的三角形
//从第m列,向上计算,
//首先是斜率最大的那一条,确定为j = [(i+k-2)/k],还有判断符合条件的同学(第i列)
//更新mn[i] = min(j,d_x);

 

bug记录:

(1)

  计算斜率中,因为可能有误差,所以最好用int类型dx,dy保存

  且这样方便取模运算

  比如k' > k 就可以写成 dy' * dx > dy * dx

  但是注意数据范围,这样可能会爆int 最好写成 1LL * dy' * dx > 1LL * dy * dx

(2)结果mn改成long long 类型之后,sum居然忘了改类型

#include<bits/stdc++.h>
using namespace std;
#define ll long long

const int N=2e5+10;

struct node
{
    int x,y;
}d[N];
int pre[N];     //pre[i]表示第i列,x坐标最小的同学,的x坐标 
int n,m,k,q;    //已经坐下了k个人,有q个换座位事件发生
ll mn[N];      //mn[i]表示第i列不能看见讲台的第一名同学,坐在第mn[i]行
ll sum=0;        //表示目前剩下多少个好位置

void input()
{
    for(int i=1;i<=k;i++)
        scanf("%d%d",&d[i].x, &d[i].y);
}

void prepare()
{
    for(int i=1;i<=m;i++)
        pre[i]=mn[i]=n+1;

    for(int i=1;i<=k;i++)
        if( pre[d[i].y] > d[i].x )
            pre[d[i].y] = d[i].x ;
}
void calculate()
{
    //先处理右上三角形
    int dy=0,dx=1;
    for(int i=1;i<=m;i++)
    {
        if(i==1 ) 
        {
            mn[i] = pre[i];
            continue;
        }
        if( 1LL*(i-1)*dx > 1LL*dy*pre[i] )
            dx=pre[i],dy=i-1;
        mn[i] = (1LL*(i-1)*dx + dy-1) / dy ;
        //目前的mn[i]表示第一个被上三角形挡住的座位,需要通过取min更新成被三角形挡住的座位
    }
    //在处理右下三角形 
    dy=0,dx=1;
    for(int i=m;i>0;i--)
    {
        if(i==m ) 
        {
            mn[i] = min(mn[i],1LL*pre[i]);
            continue;
        }
        
        if( 1LL*(i-m)*dx < 1LL*dy*pre[i] )
            dx=pre[i],dy=i-m;
        mn[i] = min( mn[i] , (1LL*(i-m)*dx + dy+1) / dy ); 
        //取模运算,因为dy小于0
        //所以ceil是选择+dy+1, 
    }
    
    sum=0;
    for(int i=1;i<=m;i++)
        sum += mn[i]-1;
}

int main()
{
    scanf("%d%d%d%d",&n,&m,&k,&q);
    
    input();
    while(q--)//200次调整,每次全部重新计算就行
    {
        int pos;
        scanf("%d",&pos);
        scanf("%d%d",&d[pos].x ,&d[pos].y);
        
        prepare();
        calculate();
        printf("%d\n",sum);
    }

    return 0;
}
View Code

 

posted @ 2022-09-11 20:28  心若笺诗  阅读(20)  评论(0编辑  收藏  举报