zoukankan      html  css  js  c++  java
  • 【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 ceil$。

    我们不难得出:从$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
    ")
     4 #define XFZBL printf("Impossible
    ");
     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 }
  • 相关阅读:
    单链表的反转
    .tar.xz压缩文件的解压
    leetcode Excel Sheet Column Number python
    leetcode Excel Sheet Column Title python
    leetcode Largest Number python
    leetcode Majority Element python
    leetcode Word Break python
    sed命令导致rc.local软链接失效
    Steam内存测试工具
    Ceph pg_num计算
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/9806354.html
Copyright © 2011-2022 走看看