【NOIP Round #6】抉择题解

题目描述

给定一个长度为 n 的非负整数序列 [a1,…,an],求它的一个子序列 [ai1,ai2,…,aik] (1≤i1<i2<⋯<ik≤n),使得 ∑k−1j=1(aijandaij+1) 最大。你只需要输出这个最大值即可。

这里,and 是指二进制按位与。

子序列的定义是:从原序列中任意删除若干个(可以是 0 个)数,将剩下的数按原来的相对顺序拼起来,得到的序列。

输入格式

第一行一个正整数 n。接下来一行 n 个整数 a1∼an。

输出格式

输出一个整数,为 ∑k−1j=1(aijandaij+1) 的最大值。

样例

样例输入 1
5
1 2 3 1 3
样例输出 1
5
样例 1 解释

一种最优解为:取子序列为 [a2,a3,a5]。

样例输入 2
2
1000000000000 987654321234
样例输出 2
965637836800
样例 3,4

见下发文件。

数据范围

所有数据均满足:1≤n≤106,0≤ai≤1012。

  • 子任务 1(20 分):n≤20。
  • 子任务 2(25 分):n≤5000。
  • 子任务 3(20 分):n≤105,ai<512。
  • 子任务 4(15 分):n≤2×105,每个 ai 都是在 [0,1012] 独立均匀随机生成的。
  • 子任务 5(20 分):无特殊限制。

思路

直接写题目即可。

代码见下

#include<bits/stdc++.h> 
using namespace std;
long long n,m,a[1000006],f[1000006],qq[1000006],hh[1000006],op=0,df;
inline long long read(){
	long long x=0;
	char s=getchar();
	while(s<'0'||s>'9'){
		s=getchar();
	}
	while(s>='0'&&s<='9'){
		x=(x<<3)+(x<<1)+(s^48);
		s=getchar();
	}
	return x;
}
int main(){
	freopen("seq.in","r",stdin);
	freopen("seq.out","w",stdout);
	cin>>n;
	for(int i=1;i<=n;i++){
		//cin>>aa[i];
		a[i]=read();
	}
	for(int i=1;i<=n;i++){
        for(int j=hh[0];j!=0;j=hh[j]){
            f[i]=max(f[i],f[j]+(a[i]&a[j]));
        }
        hh[i-1]=i;
        qq[i]=i-1;
        for(int j=hh[0];j!=0&&j<=i-1;j=hh[j]){
            if(f[j]+a[j]<=f[i]){
                qq[hh[j]]=qq[j];
                hh[qq[j]]=hh[j];
            }
        }
    }
    cout<<f[n]<<endl;
	return 0;
}

posted @ 2025-10-27 20:21  bz02_2023f2  阅读(2)  评论(0)    收藏  举报  来源