[正睿集训2021] 杂题再讲

Posted C202044zxy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[正睿集训2021] 杂题再讲相关的知识,希望对你有一定的参考价值。

你没看错就是 \\(2021\\) 年的题,他就是诈尸了。

Bank Security Unification

题目描述

点此看题

给定长度为 \\(n\\) 的数列,希望您从中选出一个子序列,使得相邻两项按位与之和最大。

\\(2\\leq n\\leq 10^6,a_i\\leq 10^12\\)

解法

首先不难想到一个 \\(dp\\),设 \\(dp[i]\\) 表示考虑前 \\(i\\) 个数,子序列的结尾是 \\(a_i\\) 的最大权值。

考虑这样一个 \\(\\tt observation\\):如果 \\(a_j\\)\\(a_k\\) 的最高位相同,并且 \\(j<k\\)那么从 \\(k\\) 转移一定比从 \\(j\\) 转移更优,这是因为 \\(a_i\\and a_k+a_k\\and a_j\\geq a_i\\and a_j\\)

这说明了对于每个数位我们只需要保留离 \\(i\\) 最近的一个数,把他们存下来暴力转移时间复杂度 \\(O(n\\log n)\\)

#include <cstdio>
#include <iostream>
using namespace std;
const int M = 1000005;
#define int long long
int read()

	int x=0,f=1;char c;
	while((c=getchar())<\'0\' || c>\'9\') if(c==\'-\') f=-1;
	while(c>=\'0\' && c<=\'9\') x=(x<<3)+(x<<1)+(c^48);c=getchar();
	return x*f;

int n,a[M],p[M],dp[M];
signed main()

	n=read();
	for(int i=1;i<=n;i++)
	
		a[i]=read();dp[i]=dp[i-1];
		for(int j=0;j<40;j++) if(p[j])
			dp[i]=max(dp[i],dp[p[j]]+(a[i]&a[p[j]]));
		for(int j=0;j<40;j++)
			if(a[i]&(1ll<<j)) p[j]=i;
	
	printf("%lld\\n",dp[n]);

以上是关于[正睿集训2021] 杂题再讲的主要内容,如果未能解决你的问题,请参考以下文章

正睿2019暑假集训正睿892 蔡老板与宝藏

10.2 正睿国庆集训测试1

正睿2018暑假集训 比赛题选做

7.29:正睿集训(人工智能峰会)day2

codeforces 杂题训练

杂题总汇HDU-5215 Cycle