BZOJ 5092 分割序列

版权声明:写得不好,转载请通知一声,还请注明出处,感激不尽 https://blog.csdn.net/As_A_Kid/article/details/85015180

Problem

BZOJ

Solution

f ( b , n ) = max i = 0 n ( ( b 1 b 2 . . . b i ) + ( b i + 1 b i + 2 . . . b n ) ) f(b,n)=\max_{i=0}^n((b_1 \oplus b _2 \oplus...\oplus b_i)+(b_{i+1} \oplus b_{i+2} \oplus...\oplus b_n))
转化一下
f ( b , i ) = max j = 0 i ( p r e j + p r e j p r e i ) f(b,i)=\max_{j=0}^i(pre_j+pre_j\oplus pre_i)
题目就转化为了对于每个 i i ,求出一个最优的 j ( j < i ) j(j<i)
我们思考一下对于一定的 x x y y 要怎么样 y + y x y+y\oplus x 最大

对二进制下的单独一位进行考虑,会发现式子的真值表是这样的

x\y 0 1
0 0 1
1 1 1

那么每一位都是独立的,从高到低贪心即可。那么我们就需要查询在是否存在一个 p i p\leq i p r e p pre_p 是前几位贪心结果的超集,用高维前缀和解决。
时间复杂度 O ( ( v + n ) log v ) O((v+n)\log v)

Code

#include <cstring>
#include <cstdio>
#define rg register
using namespace std;
typedef long long ll;
const int maxn=300010,maxm=1100000;
template <typename Tp> inline int getmin(Tp &x,Tp y){return y<x?x=y,1:0;}
template <typename Tp> inline int getmax(Tp &x,Tp y){return y>x?x=y,1:0;}
template <typename Tp> inline void read(Tp &x)
{
    x=0;int f=0;char ch=getchar();
    while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    if(ch=='-') f=1,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    if(f) x=-x;
}
int n,mx,l,N,ans,mi[25],a[maxn],f[maxm];
int main()
{
	read(n);mi[0]=1;
	for(int i=1;i<=20;i++) mi[i]=mi[i-1]<<1;
	memset(f,0x3f,sizeof(f));
	for(rg int i=1;i<=n;i++)
	{
		read(a[i]);a[i]^=a[i-1];
		getmin(f[a[i]],i);getmax(mx,a[i]);
	}
	for(N=1;N<=mx;N<<=1) ++l;
	for(int i=0;i<l;i++)
	  for(rg int j=0;j<N;j++)
	    if(!(j&mi[i]))
	      getmin(f[j],f[j|mi[i]]);
	for(rg int i=1;i<=n;i++)
	{
		ans=0;
		for(int j=l-1;~j;j--)
		  if(!(a[i]&mi[j])&&f[ans|mi[j]]<=i)
		    ans|=mi[j];
		printf("%d\n",ans+(ans^a[i]));
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/As_A_Kid/article/details/85015180
今日推荐