题面去内网找
这是这一组题里最好的一道。这个处理相当于把原数<<1后,如果第n位上有值,补到第0位上。其实硬算就行。。如果对手在第i次操作后进行处理,相当于把a1~i异或后左移了一次,而对于取不同的i,共会产生m+1种不同的结果,只要去找初始选取的数值,^每一种结果去比较。
但我们发现,最多有2^30种不同的初始值。。。但是,对于确定的m+1种结果,我们可以确定每一位异或0还是1使得结果最大,而且对手会根据我选的更改答案。。。那么可以对m+1种结果造一颗trie树,然后从高位开始贪心。如果子节点同时有0和1,那么选哪一个都会被对手改成对答案贡献为0,但如果只有其中一个,对手就没有更改的选择,那么一定会对答案产生贡献。依次逐位贪心,dfs修改答案即可。
#pragma GCC optimize("O3")
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 100005
#define ll long long
using namespace std;
int read()
{
int sum=0,f=1;char x=getchar();
while(x<'0'||x>'9'){if(x=='-')f=-1;x=getchar();}
while(x>='0'&&x<='9'){sum=(sum<<1)+(sum<<3)+x-'0';x=getchar();}
return sum*f;
}
ll n,m,a[N],xp[35],s[N],sum[N],ans1,ans2;
struct trie
{
trie *ch[2];int end;
trie(){end=0;memset(ch,0,sizeof(ch));}
}*root=new trie();
ll get(ll x)
{
if(x&xp[n-1])return(x<<1)&(xp[n]-1)|1;
return (x<<1)&(xp[n]-1);
}
void insert(ll x)
{
trie *now=root;
for(int i=n-1;i>=0;i--)
{
bool k=x&xp[i];
if(!now->ch[k])now->ch[k]=new trie();
now=now->ch[k];
}
now->end=1;
}
void dfs(trie* x,int k,ll sum)
{
if(!k)
{
if(sum>ans1){ans1=sum,ans2=0;}
if(sum==ans1)ans2++;
return;
}
if(x->ch[0]&&x->ch[1])
{
dfs(x->ch[0],k-1,sum);
dfs(x->ch[1],k-1,sum);
}
else
{
if(x->ch[0])
dfs(x->ch[0],k-1,sum+xp[k-1]);
else
dfs(x->ch[1],k-1,sum+xp[k-1]);
}
}
int main()
{
n=read();m=read();
for(int i=1;i<=m;i++)a[i]=read();
xp[0]=1;for(int i=1;i<=n;i++)xp[i]=xp[i-1]*2ll;
sum[1]=a[1];for(int j=2;j<=m;j++)sum[j]=sum[j-1]^a[j];
for(int i=0;i<=m;i++)
{
ll x=get(sum[i])^sum[m]^sum[i];
insert(x);
}
dfs(root,n,0);
printf("%lld\n%lld",ans1,ans2);
}


被折叠的 条评论
为什么被折叠?



