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 }

猜你喜欢

转载自www.cnblogs.com/asdfsag/p/11517805.html