[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); }