[2016北京集训测试赛4]打地鼠-[思考题]

Description

Solution

我们先只考虑一只地鼠的情况,依题意得,在某一个时刻该地鼠的可能停留位置是一个公差为2的等差数列。我们设这个等差数列的两端为[L,R]。则如果区间[L+1,R-1]的格子被打实际上是不会影响L和R的(列一个等差数列实际模拟一下就发现啦)。而如果格子L被打,则L+2;如果格子R被打,则R-2。打了格子后,别忘了L--,R++。

嗯根据以上性质,我们可以知道,地鼠1,3,5,7,9...的L是非递减的,地鼠2,4,6,8,10...的L也是非递减的。

然后看一下数据范围,初步判定时间复杂度为线性的。也就是说,我们要在O(1)时间内判断地鼠们的L有多少个和当前被打格子x相等。这个时候,奇偶性相同的地鼠L是非递减这个性质就很重要了。我们记录数组_l,_l[i]=x表示从第x只地鼠开始,往后所有与x奇偶性相同的地鼠的L会>=i。那地鼠们的L--怎么处理呢?我们把数组全部强行挪一位啊(可以用指针操作)。

对于数组_r,_r[i]=x表示从第x只地鼠开始,往前所有与x奇偶性相同的地鼠的R会<=i。处理方式和性质同上。

哦对了,记得处理死去的地鼠。只有地鼠的L和R同时被打中,地鼠才会死亡。我们只需要查询一下数组_l和_r就可以判断出有哪些地鼠死亡。由于死亡的地鼠应该是一个区间,可以差分。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int N=1000010;
int n,m,x;
int _l[N<<2],*p_l=_l+N,l[N],L;
int _r[N<<2],*p_r=_r+N,r[N],R;
int not_alive[N<<2];
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) p_l[i]=p_r[i]=i;
    p_l[0]=1;p_r[n+1]=n;
    for (int i=1;i<N;i++) p_l[n+i]=n+1;
    for (int i=1;i<=m;i++)
    {
        scanf("%d",&x);
        p_l[x+2]=p_l[x];L=p_l[x];
        p_r[x-2]=p_r[x];R=p_r[x];
        if (L<=R) not_alive[L]++,not_alive[R+2]--;
        p_l++;p_l[2]=p_l[0];
        p_r--;p_r[n-1]=p_r[n+1];
    }
    for (int i=1;i<=n;i++)
        for (int j=p_l[i];j<p_l[i+2];j+=2) l[j]=i;
    for (int i=n;i;i--)
        for(int j=p_r[i];j>p_r[i-2];j-=2) r[j]=i;
    for (int i=3;i<=n;i++) not_alive[i]+=not_alive[i-2];
    for (int i=1;i<=n;i++)
        not_alive[i]?printf("0 "):printf("%d ",(r[i]-l[i])/2+1);
}
原文地址:https://www.cnblogs.com/coco-night/p/9642938.html