← 回到所有文章

CF1208F Bits And Pieces 题解

前言 如果你还不会 SOSDP,其实也没关系,这道题可以使用更简单的方法完成。 正文 0x00 题目分析 首先肯定考虑从高位开始贪心,而且这样的贪心是显然正确的。并且这样的操作具有二进制集合性质,可以…

题解文章的简约插画封面

前言

如果你还不会 SOSDP,其实也没关系,这道题可以使用更简单的方法完成。

正文

0x00 题目分析

首先肯定考虑从高位开始贪心,而且这样的贪心是显然正确的。并且这样的操作具有二进制集合性质,可以从集合的元素进行考虑。那么我们从高位贪心就可以抽象为检查某个元素 xx 是否有两个被集合同时包含,若有则将 xx 元素纳入当前的答案。接下来考虑次高位 yy 元素,但是现在具有限制条件,必须还要同时包含了 xx 元素,若这样的集合有两个才行。

那么可以对每个集合把他的所有子集才出来,并且记录每一次子集出现了多少次。但是现在的时间复杂度达到了 O(2log⁡an)=O(na)\mathcal{O}\left(2^{\log a}n\right)=\mathcal{O}\left(na\right),显然无法通过。考虑优化,我们只需要检查某个子集是否出现了 22 次即可,那么当某个子集已经被标记了两次时,这个子集的子集都不需要再次访问了。可以使用一个递归实现每次减少一个元素。最终时间复杂度 O(2log⁡a+nlog⁡a)=O(nlog⁡a+a)\mathcal{O}\left(2^{\log a}+n\log a\right)=\mathcal{O}\left(n\log a+a\right)。

0x01 代码实现

AC CODE

#include<bits/stdc++.h>
// #define ONLINE_JUDGE
#define INPUT_DATA_TYPE int
#define OUTPUT_DATA_TYPE int
INPUT_DATA_TYPE read(){register INPUT_DATA_TYPE x=0;register char f=0,c=getchar();while(c<'0'||'9'<c)f=(c=='-'),c=getchar();while('0'<=c&&c<='9')x=(x<<3)+(x<<1)+(c&15),c=getchar();return f?-x:x;}void print(OUTPUT_DATA_TYPE x){register char s[20];register int i=0;if(x<0){x=-x;putchar('-');}if(x==0){putchar('0');return;}while(x){s[i++]=x%10;x/=10;}while(i){putchar(s[--i]+'0');}return;}

int arr[2000010],vis[2000010],sum[2000010];

void addE(int val,int pos){
    if(sum[val]>1|vis[val]==pos) return;//优化
    ++sum[val],vis[val]=pos;
    register int i;
    for(i=std::__lg(val);~i;--i)
        addE((~(1<<i))&val,pos);
}

int main(){
	#ifndef ONLINE_JUDGE
	freopen("name.in", "r", stdin);
	freopen("name.out", "w", stdout);
	#endif

    register int i,j,k,val,ans=0;

    int n=read();
    for(i=n-1;~i;--i) arr[i]=read();
    for(i=0;i<n;++i){
        val=arr[i];
        if(i>1){
            k=0;//k就是当前纳入考虑的元素集合
            for(j=20;~j;--j)//从高位贪心
                if(!(val&(1<<j))&&sum[k|(1<<j)]>1)
                    k|=(1<<j);
            ans=std::max(ans,val|k);
        }
        addE(val,i+1);
    }

    print(ans);

	#ifndef ONLINE_JUDGE
	fclose(stdin);
	fclose(stdout);
	#endif
    return 0;
}

总结

这样二进制位运算求 max 通常可以从高位贪心,然后通过值域较小的特点计算即可。

谢谢你,读到这里。

本文同步自洛谷专栏,保留原始正文与发布时间。在洛谷查看原文 ↗

搜索文章

输入关键词,发现一些值得阅读的文字。

探索文字里的小小世界esc 关闭