当前位置: 代码迷 >> 综合 >> trie+dfs+贪心 big
  详细解决方案

trie+dfs+贪心 big

热度:16   发布时间:2023-12-08 14:41:40.0

题面去内网找

这是这一组题里最好的一道。这个处理相当于把原数<<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]);elsedfs(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);
}