AGC012E

状压就状压,考试时干嘛分层……
通过状压枚举前后缀就可以枚举所有情况了。

预处理left[i,j]表示在i行走值已经减半j次能往左走到哪,同理有right。
我们每次从i点出发,用行走值v可以走到[l,r]。
那么你需要将接下来的行走值分成两部分然后覆盖[1,l-1]和[r+1,n]。
我们希望预处理一个mi[i]表示用行走值中的一部分覆盖[1,i],另一部分能覆盖[x,n],x的最小值是多少。
然后为了这个先状压DP一下,设f[s]表示用s集合里的行走值覆盖[1,x]最大的x是多少,每次可以枚举一个不在s里的i然后转移,用这个i去覆盖接下来一段。
同理会有个g[s]表示覆盖[x,n]。
于是接下来再枚举拿哪些覆盖前缀即可处理mi。
在预处理时不考虑扔掉不跳跃的行动力,最后手动处理一下。

还有记得没有行动力也可以通过跳转来占据一个点,所以要多加一个行动力为0的段。

code:

#include<iostream>
#include<cstdio>
#include<cstring>
const int N=2e5+2;
int n,bit,vl[19],dp[N],pos[N],dpl[1<<18],dpr[1<<18],to_l[N][19],to_r[N][19];
//dp[i]: 左侧覆盖1~i,右侧最多能够覆盖dp[i]~n(不使用未跳跃)

template <class T> inline void apn(T &x,const T y){
	if(x>y) x=y;
}

template <class T> inline void apx(T &x,const T y){
	if(x<y) x=y;
}

inline int nxi(){
	int x=0;
	char c;
	while(((c=getchar())>'9'||c<'0')&&c!='-');
	const bool f=c=='-'&&(c=getchar());
	while(x=x*10-48+c,(c=getchar())>='0'&&c<='9');
	return f?-x:x;
}

int main(){
#ifndef ONLINE_JUDGE
	freopen("d.in","r",stdin);
#endif
	memset(dp,1,sizeof(dp));
	memset(dpr,1,sizeof(dpr));
	n=nxi(),vl[0]=nxi();
	for(;vl[bit];++bit){
		vl[bit+1]=vl[bit]>>1;
	}
	for(int i=1;i<=n;++i){
		pos[i]=nxi();
	}
	for(int i=0;i<=bit;++i){
		for(int s=1,t;s<=n;s=t+1){
			t=s;
			while(t<n&&pos[t+1]-pos[t]<=vl[i]) ++t;
			for(int j=s;j<=t;++j){
				to_l[j][i]=s,to_r[j][i]=t;
			}
		}
	}
	dpl[0]=0,dpr[0]=n+1;
	for(int i=0;i<1<<bit;++i){
		for(int j=1;j<=bit;++j){
			if(!(i&(1<<(j-1)))){
				apx(dpl[i|1<<(j-1)],to_r[dpl[i]+1][j]);
				if(dpr[i]){
					apn(dpr[i|1<<(j-1)],to_l[dpr[i]-1][j]);
				}
				else dpr[i|1<<(j-1)]=0;
			}
		}
	}
	for(int i=0;i<1<<bit;++i){
		apn(dp[dpl[i]],dpr[((1<<bit)-1)^i]);
	}
	for(int i=n;i;--i){
		apn(dp[i-1],dp[i]);
	}
	for(int i=1;i<=n;++i){
		puts(dp[to_l[i][0]-1]<=to_r[i][0]+1?"Possible":"Impossible");
	}
	return 0;
}