Kattis - bitwise Bitwise (RMQ+尺取+树上dfs)

Posted asdfsag

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kattis - bitwise Bitwise (RMQ+尺取+树上dfs)相关的知识,希望对你有一定的参考价值。

题意:有一个长度为n的序列,让你把它分成k段,段内元素取or,段间取and,求能够得到的最大值。

这个算法是我和xz场上yy出来的,然而时间不够了没写出来,而且时间复杂度是$O(nlogn+nlogA)$的比官方题解都要低...(但是常数大了点)

设最大值为ans,我们假设S&ans=S,看看S能否用k条线段凑出来,则将原问题转化成了一个判定问题。从高到低一位一位地考虑,最多只需进行$O(logA)$次判定。

如何进行判定呢?

首先将原数组复制一倍接到后面,然后进行两次尺取。第一次求出每个左端点l所对应的能够覆盖S的最小的右端点r并把它作为一条线段放进数组里(能够覆盖S的意思是S的每一位上的1都可以在[l,r]区间里的某个元素中取到,可以用RMQ预处理区间or然后$O(1)$判断),第二次则对这些线段进行尺取,求出每条线段右边第一条和它不相交的线段,将每条线段与这样的线段连边,可以得到一棵树(或者森林,若为森林则将所有树和一个虚节点连边即可变成一棵树),只需要检查一下这棵树上是否有一个结点的l和与它距离为k的父亲结点的r的区间长度r-l+1是否小于n,从根节点dfs一遍即可。

代码:(我写了两份,第一份怕爆栈所以手写了数组模拟栈,第二份是普通的dfs)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N=1e6+10;
 5 int n,k,a[N],ST[N][20],Log[N],nl,hd[N],ne,q[N],tp;
 6 void build() 
 7     for(int i=1; i<=2*n; ++i)ST[i][0]=a[i];
 8     for(int k=1; k<=Log[2*n]; ++k)
 9         for(int i=1; i+(1<<k)-1<=2*n; ++i)
10             ST[i][k]=ST[i][k-1]|ST[i+(1<<(k-1))][k-1];
11 
12 int qry(int L,int R) 
13     int k=Log[R-L+1];
14     return ST[L][k]|ST[R-(1<<k)+1][k];
15 
16 struct D int l,r; line[N];
17 struct E int v,nxt; e[N];
18 struct ND int u,dep; sta[N];
19 void addedge(int u,int v) e[ne]= v,hd[u],hd[u]=ne++;
20 bool dfs() 
21     sta[tp=0]= nl,0;
22     while(~tp) 
23         int u=sta[tp].u,dep=sta[tp--].dep;
24         q[dep]=u;
25         if(dep>=k&&line[q[dep-k+1]].r-line[u].l+1<=n)return 1;
26         for(int i=hd[u]; ~i; i=e[i].nxt)sta[++tp]= e[i].v,dep+1;
27     
28     return 0;
29 
30 bool ok(int S) 
31     nl=0;
32     for(int i=1,j=1; i<=2*n; ++i) 
33         if(j<i)j=i;
34         for(; j<=2*n&&(qry(i,j)&S)!=S; ++j);
35         if(j<=2*n)line[nl++]= i,j;
36     
37     for(int i=0; i<=nl; ++i)hd[i]=-1;
38     ne=0;
39     for(int i=0,j=0; i<nl; ++i) 
40         for(; j<nl&&line[j].l<=line[i].r; ++j);
41         addedge(j,i);
42     
43     return dfs();
44 
45 int solve() 
46     int ret=0;
47     for(int i=30; i>=0; --i)if(ok(ret|(1<<i)))ret|=1<<i;
48     return ret;
49 
50 int main() 
51     Log[0]=-1;
52     for(int i=1; i<N; ++i)Log[i]=Log[i>>1]+1;
53     scanf("%d%d",&n,&k);
54     for(int i=1; i<=n; ++i)scanf("%d",&a[i]);
55     for(int i=1; i<=n; ++i)a[i+n]=a[i];
56     build();
57     printf("%d\n",solve());
58     return 0;
59 
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N=1e6+10;
 5 int n,k,a[N],ST[N][20],Log[N],nl,hd[N],ne,q[N];
 6 void build() 
 7     for(int i=1; i<=2*n; ++i)ST[i][0]=a[i];
 8     for(int k=1; k<=Log[2*n]; ++k)
 9         for(int i=1; i+(1<<k)-1<=2*n; ++i)
10             ST[i][k]=ST[i][k-1]|ST[i+(1<<(k-1))][k-1];
11 
12 int qry(int L,int R) 
13     int k=Log[R-L+1];
14     return ST[L][k]|ST[R-(1<<k)+1][k];
15 
16 struct D int l,r; line[N];
17 struct E int v,nxt; e[N];
18 void addedge(int u,int v) e[ne]= v,hd[u],hd[u]=ne++;
19 bool dfs(int u,int dep) 
20     q[dep]=u;
21     if(dep>=k&&line[q[dep-k+1]].r-line[u].l+1<=n)return 1;
22     for(int i=hd[u]; ~i; i=e[i].nxt)if(dfs(e[i].v,dep+1))return 1;
23     return 0;
24 
25 bool ok(int S) 
26     nl=0;
27     for(int i=1,j=1; i<=2*n; ++i) 
28         if(j<i)j=i;
29         for(; j<=2*n&&(qry(i,j)&S)!=S; ++j);
30         if(j<=2*n)line[nl++]= i,j;
31     
32     for(int i=0; i<=nl; ++i)hd[i]=-1;
33     ne=0;
34     for(int i=0,j=0; i<nl; ++i) 
35         for(; j<nl&&line[j].l<=line[i].r; ++j);
36         addedge(j,i);
37     
38     return dfs(nl,0);
39 
40 int solve() 
41     int ret=0;
42     for(int i=30; i>=0; --i)if(ok(ret|(1<<i)))ret|=1<<i;
43     return ret;
44 
45 int main() 
46     Log[0]=-1;
47     for(int i=1; i<N; ++i)Log[i]=Log[i>>1]+1;
48     scanf("%d%d",&n,&k);
49     for(int i=1; i<=n; ++i)scanf("%d",&a[i]);
50     for(int i=1; i<=n; ++i)a[i+n]=a[i];
51     build();
52     printf("%d\n",solve());
53     return 0;
54 

 

以上是关于Kattis - bitwise Bitwise (RMQ+尺取+树上dfs)的主要内容,如果未能解决你的问题,请参考以下文章

bitwise_and 输入参数的大小不匹配

Python OpenCV —— bitwise

Bitwise Operators

markdown js-bitwise-hacks.md

Bitwise And Queries

“typedef __u16 __bitwise __le16;”是啥意思?在Linux内核中是啥意思?