【AGC012E】 Camel and Oases ST表+状压dp

题目大意:一排点,两点间有距离。 初始你有一个行走值$v$,如果相邻两点距离不超过$v$你可以自由在这两点行走。 
当$v$大于$0$时,你可以选择某一时刻突然飞到任意点,这样做后$v$会减半(下取整)。 问从每个位置初始出发能否到达所有位置。

点的数量$≤2*10^5$,$v≤2*10^5$,$|两点距离|≤10^9$。

 

我们令$l[i][j]$表示从$i$出发,一路往左走,经过所有长度不超过$v>>j$(此处的$>>$表示右移,以下都是)的边,能走到最左的点的编号。

令$r[i][j]$表示从$i$出发,一路往右走,经过所有长度不超过$v>>j$的边,能走到最右的点的编号。

令$n$表示点的数量,$m=\lceil log_2v\rceil$。

我们不难得出:从$u$号点出发,是否可以遍历完所有点的判断条件,可以转化为:

是否可以将点集分成$m+1$个块,且第$i$(从$0$到$m$)个块内边的长度均不超过$v>>i$,且第$u$号点需要在第$0$个块内。

 

那么,对于$[1,2^m)$中的每一个$i$($i$是一个二进制状态,$i$的第$j$($j$从$1$到$m$)位为$1$表示选择了图中第$j$个块)

求一个最大的$f[i]$,满足区间$[1,f[i]]$中的点能分成由状态i表示的若干个块。

同理,求一个最小的$g[i]$,满足区间$[g[i],n]$中的点能分成由状态i表示的若干个块。

求这个可以通过l和r的值+状压$dp$实现,时间复杂度是$O(v\ log\ v)$。

我们令$o=2^m-2$。

我们发现,若存在$i$,使得$r[f[i]][0]>=l[g[o$^$i]][0]$,那么从区间$[\ l[g[o$^$i]][0]\ ,\ r[f[i]][0]\ ]$中出发的点,显然可以遍历玩所有点。

我们可以$O(1)$打上一个标记,求答案的时候$O(n)$扫一遍,判断某个点是否被打了标记即可。

总时间复杂度:$O(n\ log\ v+v\ log\ v)$。

 1 #include<bits/stdc++.h>
 2 #define M 400005
 3 #define YXQAK printf("Possible\n")
 4 #define XFZBL printf("Impossible\n");
 5 using namespace std;
 6 
 7 int a[M]={0},n,m,v,l[20][M]={0},r[20][M]={0};
 8 int f[M]={0},g[M]={0},p[M]={0};
 9 
10 int main(){
11     scanf("%d%d",&n,&v);
12     for(int i=1;i<=n;i++) scanf("%d",a+i);
13     sort(a+1,a+n+1); 
14     for(int j=0,V=v;V;j++,V>>=1){
15         m=max(m,j);
16         for(int i=1;i<=n;i++){
17             int I=i+1;
18             while(I<=n&&a[I]-a[I-1]<=V) I++;
19             I--;
20             for(int ii=i;ii<=I;ii++) 
21             l[j][ii]=i,r[j][ii]=I;
22             i=I;
23         }
24     }
25     m++; 
26     for(int i=1;i<=n;i++) l[m][i]=r[m][i]=i;
27     for(int i=0;i<(1<<m);i++) g[i]=n; f[0]=1;
28     for(int i=1;i<(1<<m);i++){
29         int now=1;
30         for(int j=m-1;~j;j--)
31         if((1<<j)&i)
32         f[i]=max(f[i],r[j+1][f[i^(1<<j)]]+1);
33         
34         now=n;
35         for(int j=m-1;~j;j--)
36         if((1<<j)&i)
37         g[i]=min(g[i],l[j+1][g[i^(1<<j)]]-1);
38     }
39     
40     for(int i=0;i<(1<<m);i++){
41         if(r[0][f[i]]+1>=l[0][g[(1<<m)-i-1]])
42         p[l[0][g[(1<<m)-i-1]]]++,p[r[0][f[i]]+1]--;
43     }
44     for(int i=1;i<=n;i++){
45         p[i]+=p[i-1];
46         if(p[i]) YXQAK;
47         else XFZBL;
48     }
49 }
posted @ 2018-10-17 19:04  AlphaInf  阅读(200)  评论(0编辑  收藏  举报