ARC100E题解

垃圾 \(O(3^n)\) 做法/kk

对于每个 \(k\) 分别计算答案,注意到 \(i\) 一定是 \(k\) 的子集所以先枚举一个 \(i\),此时 \(j\) 应该是被钦定 \(i\)\(1\) 的部分为 \(0\),剩下 \(k\) 的子集部分可以随意取 \(0/1\)

于是弄一个类似前缀和的东西 \(f[S]\)\(S\) 的第 \(i\) 位为 \(0/1/2\) 表示这一位被 钦定为 \(0/1\)/都可以,这个东西随便转移一下就好了,容易发现复杂度为 \(O(3^n)\)

总复杂度 \(O(3^n)\),被 \(O(n2^n)\) 吊起来锤/kk

容易发现这个东西是非常容易被薄纱的,来考虑一个很神奇的性质:

\(i|j\subseteq k\),那么 \(i|j\leq k\)

根据这个性质,对每个 \(k\) 分别计算答案的时候可以考虑计算 \(i|j\subseteq k\)

也就是说我们可以计算 \(k\) 子集中的最大值和次大值,然后将其加起来。

计算方法和 FWT 还是一样的,按位考虑即可。

复杂度 \(O(n2^n)\)

#include<cstdio>
#include<cctype>
const int M=1<<18;
int n;
inline int max(const int&a,const int&b){
	return a>b?a:b;
}
struct data{
	int mx1,mx2;
	data(const int&mx1=0,const int&mx2=0):mx1(mx1),mx2(mx2){}
	inline data operator+(const data&it){
		return mx1==it.mx1?data(mx1,mx1):mx1>it.mx1?data(mx1,max(mx2,it.mx1)):data(it.mx1,max(mx1,it.mx2));
	}
	inline data&operator+=(const data&it){
		return*this=*this+it;
	}
}f[M];
inline int read(){
	int n(0);char s;while(!isdigit(s=getchar()));while(n=n*10+(s&15),isdigit(s=getchar()));return n;
}
inline void write(int n){
	static char s[15];int top(0);while(s[++top]=n%10^48,n/=10);while(putchar(s[top]),--top);putchar(10);
}
signed main(){
	n=read();for(int i=0;i<(1<<n);++i)f[i]=data(read(),0);
	for(int len=1;len<(1<<n);len<<=1)for(int k=0;k<(1<<n);k+=len<<1)for(int i=0;i<len;++i)f[i|k|len]+=f[i|k];
	for(int mx(f[0].mx1),i=1;i<(1<<n);++i)write(mx=max(mx,f[i].mx1+f[i].mx2));
}
posted @ 2022-08-20 08:30  Prean  阅读(19)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};