题目大意
给定一个序列,试求出两个长度不小于 k k k 的连续子序列,分别使得他们的二进制或值和二进制与值最大,输出这两个最值。
对于 100 % 100\% 100% 的数据, 1 ≤ k ≤ n ≤ 1000000 1≤k ≤n ≤ 1000000 1≤k≤n≤1000000,数列中的每个数在 [ 0 , 2 3 1 − 1 ] [0,2^31-1] [0,231−1] 范围内。
解题思路
显然,二进制或值,所有与起来就行了。
对于二进制与值,有一个定理:两个数相与,结果不会比这两个数任何一个大。
那么不用取长度 ≥ \ge ≥ 的子序列,只需要取长度 = k =k =k 的子序列即可,因为根据上面的定理,长度再大也不会比长度为 k k k 的大。
二进制与值取连续 k k k 个某二进制位都为 1 1 1 的所有贡献合计即可。
做法一
二进制或值,同上。
二进制与值直接 O ( n log n ) \mathcal{O}(n \log n) O(nlogn) 递推即可。
故时间复杂度为 O ( n log n ) \mathcal{O}(n \log n) O(nlogn)。
做法一
二进制或值,同上。
二进制与值取连续
k
k
k 个
1
1
1,那么用 ST
表或 线段树 维护区间与值即可。
故时间复杂度为 O ( n log n ) \mathcal{O}(n \log n) O(nlogn)。
AC CODE
做法一
#include <bits/stdc++.h>
using namespace std;
#define int long long
namespace Fread
{
const int SIZE = 1 << 21;
char buf[SIZE], *S, *T;
inline char getchar()
{
if (S == T)
{
T = (S = buf) + fread(buf, 1, SIZE, stdin);
if (S == T)
return '\n';
}
return *S++;
}
}
namespace Fwrite
{
const int SIZE = 1 << 21;
char buf[SIZE], *S = buf, *T = buf + SIZE;
inline void flush()
{
fwrite(buf, 1, S - buf, stdout);
S = buf;
}
inline void putchar(char c)
{
*S++ = c;
if (S == T)
flush();
}
struct NTR
{
~NTR()
{
flush();
}
} ztr;
}
#ifdef ONLINE_JUDGE
#define getchar() Fread :: getchar()
#define Fwrite :: putchar()
#endif
int read()
{
int x = 0;
char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9')
{
x = x * 10 + c - '0';
c = getchar();
}
return x;
}
void write(int x)
{
if(x > 9)
{
write(x / 10);
}
putchar(x % 10 + '0');
}
int n, k;
int a[1000007];
int cnt[10000007];
int mmax;
int anss1, anss2;
void del(int x)
{
int j = 1, p = 0;
while(x >= j)
{
if(x & j) cnt[p]--;
p++;
j <<= 1;
}
}
void add(int x)
{
int j = 1, p = 0;
while(x >= j)
{
if(x & j) cnt[p]++;
p++;
j <<= 1;
}
}
int num()
{
int ans = 0;
for(int i = 0; i <= 50; ++i)
if(cnt[i] == k) ans += (1 << i);
return ans;
}
signed main()
{
n = read();
k = read();
for(int i = 1; i <= n; ++i) a[i] = read(), anss2 |= a[i], mmax = max(mmax, a[i]);
for(int i = 1; i <= k; ++i)
{
add(a[i]);
}
anss1 = max(anss1, num());
for(int i = 2; i <= n - k + 1; ++i)
{
del(a[i - 1]);
add(a[i + k - 1]);
anss1 = max(anss1, num());
}
write(anss2);
putchar(' ');
write(anss1);
putchar('\n');
}
做法二
#include <bits/stdc++.h>
using namespace std;
int n, k;
int a[1000007];
int ans, anss;
namespace Fread
{
const int SIZE = 1 << 21;
char buf[SIZE], *S, *T;
inline char getchar()
{
if (S == T)
{
T = (S = buf) + fread(buf, 1, SIZE, stdin);
if (S == T)
return '\n';
}
return *S++;
}
}
namespace Fwrite
{
const int SIZE = 1 << 21;
char buf[SIZE], *S = buf, *T = buf + SIZE;
inline void flush()
{
fwrite(buf, 1, S - buf, stdout);
S = buf;
}
inline void putchar(char c)
{
*S++ = c;
if (S == T)
flush();
}
struct NTR
{
~NTR()
{
flush();
}
} ztr;
}
#ifdef ONLINE_JUDGE
#define getchar() Fread :: getchar()
#define Fwrite :: putchar()
#endif
int read()
{
int x = 0;
char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9')
{
x = x * 10 + c - '0';
c = getchar();
}
return x;
}
void write(int x)
{
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
}
int tr[4000007];
void push_up(int o)
{
tr[o] = tr[o << 1] & tr[o << 1 | 1];
}
void build(int o, int l, int r)
{
if(l == r)
{
tr[o] = a[l];
return;
}
int mid = (l + r) >> 1;
build(o << 1, l, mid);
build(o << 1 | 1, mid + 1, r);
push_up(o);
}
int query(int o, int l, int r, int L, int R)
{
if(L <= l && r <= R)
{
return tr[o];
}
int mid = (l + r) >> 1;
int res = 2147483647;
if(L <= mid)
{
res &= query(o << 1, l, mid, L, R);
}
if(R > mid)
{
res &= query(o << 1 | 1, mid + 1, r, L, R);
}
return res;
}
signed main()
{
n = read();
k = read();
for(int i = 1; i <= n; ++i) a[i] = read(), anss |= a[i];
build(1, 1, n);
for(int i = 1; i <= n - k + 1; ++i)
ans = max(ans, query(1, 1, n, i, i + k - 1));
write(anss);
putchar(' ');
write(ans);
putchar('\n');
}