【题解】tty‘s sequence

本文介绍了如何解决寻找数列中长度大于等于k的子串,使得子串内数字异或值和与值最大的问题。通过分析每位数字的变化,得出结论:异或值最大即为所有数的异或,而与值最大需用线段树求解。给出的解决方案使用线段树实现了在限定时间内求解最大与值,并提供了相应的C++代码实现。
摘要由CSDN通过智能技术生成

前言

祝愿猪猪早日康复。


昨天在 202 202 202 看 QYB 和 LSC 整活(

所以没时间洗衣服了,洗澡的时候都是开水。

所以定了 12 : 00 , 12 : 01 , 12 : 02 12:00,12:01,12:02 12:00,12:01,12:02 三个闹钟想起来洗衣服,然后一觉睡到 6 : 20 6:20 6:20,室友人不在,闹钟响了(

当时觉得很奇怪为什么闹钟没响,但是太困了就继续睡了。

结果一起来看手机显示 8 : 49 8:49 8:49

马上跳起来把眼镜摘了然后叫上 DYY 一起跑。

到机房已经没了半小时了。

可以感觉到已经炸了。

r e s : 135 p t s res:135pts res:135pts


Description \text{Description} Description

给定一个长度为 n n n 的数列以及 k k k,请求出两个长度 ≥ k \ge k k 的子串,分别使得子串中的数的 o r \rm or or 值和 a n d \rm and and 值最大。

  • 对于 30 % 30\% 30% 的数据, n , k ≤ 100 n,k\le100 n,k100
  • 对于另外 30 % 30\% 30% 的数据, k ≤ 10 k\le10 k10
  • 对于 100 % 100\% 100% 的数据, 1 ≤ k ≤ n ≤ 1000000 1\le k\le n\le1000000 1kn1000000,数列中的每个数在 [ 0 , 2 31 − 1 ] [0,2^{31}-1] [0,2311] 范围内。

Solution \text{Solution} Solution

我们考虑每一位:

原数0011
新数0101
o r \rm or or0111
a n d \rm and and0001

o r \rm or or 后不可能变小, a n d \rm and and 后不可能变大。

所以 o r \rm or or 最大就是所有数 o r \rm or or 起来, a n d \rm and and 最大就是 max ⁡ { \max\{ max{ 所有长度为 k k k 的子串的 $ \rm and$ 值 } \} }

结果看到这个长度为 k k k 的子串没想到线段树(

时间复杂度 O ( ( n − k ) log ⁡ k ) \mathcal{O}((n-k)\log k) O((nk)logk)

Code \text{Code} Code

#include <iostream>
#include <cstdio>
using namespace std;

const int MAXN = 1e6 + 5;

int a[MAXN];

#define lson pos << 1
#define rson pos << 1 | 1

struct tree
{
	int l, r, val;
}t[MAXN << 2];

void pushup(int pos)
{
	t[pos].val = t[lson].val & t[rson].val;
}

void build(int pos, int l, int r)
{
	t[pos].l = l, t[pos].r = r;
	if (l == r)
	{
		t[pos].val = a[l];
		return;
	}
	int mid = (l + r) >> 1;
	build(lson, l, mid);
	build(rson, mid + 1, r);
	pushup(pos);
}

int query(int pos, int L, int R)
{
	int l = t[pos].l, r = t[pos].r;
	if (L <= l && r <= R)
	{
		return t[pos].val;
	}
	int mid = (l + r) >> 1, res = 0x7fffffff;
	if (L <= mid)
	{
		res &= query(lson, L, R);
	}
	if (R > mid)
	{
		res &= query(rson, L, R);
	}
	return res;
}

int main()
{
	int n, k, ans1 = 0, ans2 = 0;
	scanf("%d%d", &n, &k);
	for (int i = 1; i <= n; i++)
	{
		scanf("%d", a + i);
		ans1 |= a[i];
	}
	printf("%d ", ans1);
	build(1, 1, n);
	for (int i = 1; i <= n - k + 1; i++)
	{
		ans2 = max(ans2, query(1, i, i + k - 1));
	}
	printf("%d\n", ans2);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值