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

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

点的数量2105v2105||109

 

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

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

n表示点的数量,m=log2v

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

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

 

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

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

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

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

我们令o=2m2

我们发现,若存在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 @   AlphaInf  阅读(202)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示