分析:
有点套路的状压题
很显然,最多logV层,所以可以记录每一层的选取状态(第一层保证不能选)。
定义
f
1
(
m
a
s
k
)
f1(mask)
f1(mask)表示选取状态为mask时,从最左端开始连续覆盖的最右端。
定义
f
2
(
m
a
s
k
)
f2(mask)
f2(mask)表示选取状态为mask时,从最右端开始连续覆盖的最左端。
之所以要分成两段,是因为最终我们要判断从某一段开始,能否全部覆盖,所以最开始一个区间类似于询问,对每个询问,枚举左侧的选取状态,得到右侧对应的选取状态,然后看两段能否覆盖到当前这一段。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 1000010
#define INF 0x3FFFFFFF
using namespace std;
int n,v,logv;
int x[MAXN];
int f1[MAXN],f2[MAXN];
int l[22][MAXN],r[22][MAXN],cnt[22];
int find_l(int x,int pos){
pos++;
int now=upper_bound(l[x]+1,l[x]+1+cnt[x],pos)-l[x];
now--;
if(now<=0)
return pos;
return max(r[x][now],pos-1);
}
int find_r(int x,int pos){
pos--;
int now=lower_bound(r[x]+1,r[x]+1+cnt[x],pos)-r[x];
if(now>cnt[x])
return pos;
return min(l[x][now],pos+1);
}
int ans[MAXN];
int main(){
memset(f2,0x3f3f3f3f,sizeof f2);
SF("%d%d",&n,&v);
for(int i=1;i<=n;i++)
SF("%d",&x[i]);
x[0]=-INF;
x[n+1]=INF;
for(logv=0;(1<<logv)<=v;logv++);
logv++;
for(int i=0;i<logv;i++){
int v1=v>>i;
cnt[i]=1;
l[i][cnt[i]]=1;
for(int j=1;j<=n;j++)
if(x[j+1]-x[j]>v1){
r[i][cnt[i]]=j;
cnt[i]++;
l[i][cnt[i]]=j+1;
}
cnt[i]--;
}
if(cnt[0]>logv){
for(int i=1;i<=n;i++)
PF("Impossible\n");
return 0;
}
f1[0]=0;
f2[0]=n+1;
for(int mask=0;mask<(1<<logv);mask+=2)
for(int i=1;i<logv;i++)
if((mask&(1<<i))!=0){
f1[mask]=max(f1[mask],find_l(i,f1[mask^(1<<i)]));
f2[mask]=min(f2[mask],find_r(i,f2[mask^(1<<i)]));
}
for(int i=1;i<=cnt[0];i++){
int lft=l[0][i];
int rit=r[0][i];
for(int mask=0;mask<(1<<logv);mask+=2){
int mask2=((1<<logv)-2)^mask;
if(f1[mask]>=lft-1&&f2[mask2]<=rit+1){
ans[i]=1;
break;
}
}
}
int las=1;
for(int i=1;i<=n;i++){
if(i>r[0][las])
las++;
if(ans[las]==0)
PF("Impossible\n");
else
PF("Possible\n");
}
}