01字典树
来源:互联网 发布:java云计算方向学什么 编辑:程序博客网 时间:2024/05/26 05:51
Xor Sum HDU - 4825
题意:一个集合,集合中包含了N个正整数,随后 发起M次询问,每次询问中包含一个正整数 S ,之后 Zeus 需要在集合当中找出一个正整数 K ,使得 K 与 S 的异或结果最大。
分析:用01字典树,这是一颗二叉树,只有01。我们用静态数组来建树。对于每次询问,我们先得到一个值temp(temp和k的异或最大),然后在字典树中去查找这个数,如果当前点不存在,就往反方向走。其中处理的时候,所有数的长度都要相同。
#include <iostream>#include <cstring>#include <algorithm>#include <cmath>#include <cstdio>#include <vector>using namespace std;#define LL long longint node[3200010][2];LL zz[100];int h=0,rt=0;void add(LL x){ rt=0; for(int i=31;i>=0;i--) { int g=x&(1<<i)?1:0; if(node[rt][g]==-1) node[rt][g]=++h; rt=node[rt][g]; }}LL lookfor(LL x){ int rt=0; LL ans=0; for(int i=31;i>=0;i--) { int g=x&(1<<i)?1:0; if(node[rt][g]==-1) g=g^1;//长度相同,反方向一定存在 rt=node[rt][g]; ans=(ans<<1)+g;//记录值 } return ans;}int main(){ int T,case1=1; scanf("%d",&T); zz[0]=1; for(int i=1;i<=32;i++)//用数组处理,因为1<<32 是负数。 zz[i]=zz[i-1]<<1; // cout<<zz[32]<<endl; while(T--) { h=0; memset(node,-1,sizeof(node)); int n,m; scanf("%d %d",&n,&m); for(int i=0;i<n;i++) { LL x; scanf("%I64d",&x); add(x); } printf("Case #%d:\n",case1++); for(int i=0;i<m;i++) { LL x; scanf("%I64d",&x); LL temp=x^(zz[32]-1); printf("%I64d\n",lookfor(temp)); } } return 0;}
B - Chip Factory HDU - 5536
题意:给你一个数列,s1,s2,s2…sn ,然后问你
maxi,j,k(si+sj)⊕sk 的值 (which i,j,ki,j,k are three different integers between 11 and nn.)
分析:和第一题差不多,先将数列中的所有数都丢进字典树,然后开始枚举si,sj,去找sk,在枚举的时候先将si,sj在字典树中删除,然后找sk,找完之后再加上就行了。
#include <iostream>#include <cstring>#include <cmath>#include <algorithm>#include <cstdio>#include <queue>#include <vector>using namespace std;#define LL long longconst int maxn = 31000;int node[maxn][2];int a[1010],y[50],val[maxn];int tot=1;void sert(int x,int d){ int u=0; for(int i=30;i>=0;i--) { int g=(x>>i)&1; if(!node[u][g]){ node[u][g]=tot++; } val[node[u][g]]+=d; u=node[u][g]; }}void del(int x){ int u=0; for(int i=30;i>=0;i--) { int g=(x>>i)&1; val[node[u][g]]-=1; u=node[u][g]; }}int lookfor(int x){ int u=0,ans=0; for(int i=30;i>=0;i--) { int g=(x>>i)&1; if(!node[u][g]||!val[node[u][g]]) g=g^1; u=node[u][g]; ans=(ans<<1)+g; } return ans;}int main(){ int T; scanf("%d",&T); y[0]=1; for(int i=1;i<=31;i++) y[i]=y[i-1]<<1; while(T--) { memset(val,0,sizeof(val)); memset(node,0,sizeof(node)); memset(a,0,sizeof(a)); int n; tot=1; scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%d",&a[i]); sert(a[i],1); } int ans=0; for(int i=0;i<n;i++) { for(int j=i+1;j<n;j++) { int temp=(a[i]+a[j])^(y[31]-1); del(a[i]); del(a[j]); int k=lookfor(temp); ans=max(ans,k^(a[i]+a[j])); sert(a[i],1),sert(a[j],1); } } printf("%d\n",ans); } return 0;}
C - The xor-longest Path POJ - 3764
题意:给你一颗无根树,然后问你其中的任何一条路径的权值异或最大是多少。
分析:我们先建图,确定一个根,dfs来求所有点到原点的异或和,然后任何一条路径的异或 和就是两端点到根的异或相乘。
#include <iostream>#include <cstring>#include <cmath>#include <algorithm>#include <cstdio>#include <queue>#include <vector>using namespace std;#define LL long longconst int maxn = 100005;struct edge{ int to,pre; LL w;};edge e[maxn*2];int head[maxn*2],vis[maxn];LL a[maxn];LL c[maxn];int h=0;void add(int u,int v,LL w){ e[h].to=v,e[h].pre=head[u],e[h].w=w;head[u]=h; h++;}void dfs(int x,LL z){ for(int i=head[x];i>-1;i=e[i].pre) { if(!vis[e[i].to]) { a[e[i].to]=z^e[i].w; vis[e[i].to]=1; z=a[e[i].to]; dfs(e[i].to,z); z=z^e[i].w; } }}int node[maxn*35][2],val[maxn*35];int tot=1;void sert(int x,int d){ int u=0; for(int i=30;i>=0;i--) { int g=(x>>i)&1; if(!node[u][g]) node[u][g]=tot++; u=node[u][g]; val[u]+=d; }}LL lookfor(LL x){ int u=0; LL ans=0; for(int i=30;i>=0;i--)//这里和下面都要统一啊啊啊 { LL g=(x>>i)&1; if(!node[u][g]||!val[node[u][g]]) g=g^1; u=node[u][g]; ans=(ans<<1)+g; } return ans;}int main(){ int n; c[0]=1; for(int i=1;i<=31;i++) c[i]=c[i-1]<<1; while(scanf("%d",&n)!=EOF) { h=0,tot=1; memset(e,0,sizeof(e)); memset(head,-1,sizeof(head)); memset(vis,0,sizeof(vis)); memset(node,0,sizeof(node)); memset(a,0,sizeof(a)); memset(val,0,sizeof(val)); for(int i=0;i<n-1;i++) { int u,v;LL w; scanf("%d %d %I64d",&u,&v,&w); add(u,v,w); add(v,u,w); } vis[0]=1; dfs(0,0); for(int i=0;i<n;i++) sert(a[i],1); LL ans=0; for(int i=0;i<n;i++) { sert(a[i],-1); LL temp=a[i]^(c[31]-1); ans=max(ans,(a[i]^lookfor(temp))); sert(a[i],1); } printf("%I64d\n",ans); } return 0;}
bzoj 4260 Codechef REBXOR
分析:从前求一遍异或和,然后从后求一遍异或和,就行了。哎,数组开小了,WA的心痛。。
#include <iostream>#include <cstring>#include <cmath>#include <algorithm>#include <cstdio>#include <queue>#include <vector>using namespace std;#define LL long longint node1[31*400005][2];int a[400005],b[400005],b2[400005],c[400005];int tot1=1;int dp1[400005];void sert1(int x,int d){ int u=0; for(int i=31;i>=0;i--) { int g=(x>>i)&1; if(!node1[u][g]) node1[u][g]=tot1++; u=node1[u][g]; }}int findf1(int x){ int u=0,ans=0; for(int i=31;i>=0;i--) { int g=(x>>i)&1; g=g^1; if(!node1[u][g]) g=g^1; u=node1[u][g]; ans=(ans<<1)+g; } return ans;}int main(){ int n; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); b[i]=a[i]^b[i-1]; } int h=1; for(int i=n;i>=1;i--){ c[h]=a[i]; b2[h]=b2[h-1]^c[h]; h++; } sert1(0,1); for(int i=1;i<=n;i++) { int t1=findf1(b[i]); t1=t1^b[i]; dp1[i]=max(dp1[i-1],t1); sert1(b[i],1); } memset(node1,0,sizeof(node1)); tot1=1; int ans=0; sert1(0,1); for(int i=1;i<=n;i++) { int t2=findf1(b2[i]); t2=t2^b2[i]; ans=max(ans,t2+dp1[n-i]); sert1(b2[i],1); } printf("%d\n",ans); return 0;}
Best Division HDU - 5845
题意:给你一个数列,然后问你最多可以分成多少段,其中每段的长度不超过l,每段的异或和最大不超过x。
分析:有dp的思想,dp[i]:表示到i点的时候最多可以分成多少段,dp[i]=dp[j]+1(j < i&&s[i]*s[j] < =x)
到i了,我们就在字典树中去找s[i]与x的对应关系,如果s[i]找到了能和他相乘符合条件的,就将s[i]插入01字典树。…
#include <iostream>#include <cstring>#include <cstdio>#include <algorithm>#include <cmath>#include <vector>using namespace std;#define LL long long#define mod 268435456int n,x,l;LL p,q;const int maxn = 100005;LL a[maxn];int node[32*maxn][2],val[maxn*32],dp[maxn*32],fa[maxn*32];LL sum[maxn];int tot=1;void sert(int s,int c){ int u=0; for(int i=30;i>=0;i--) { int g=(s>>i)&1; if(!node[u][g]){ node[u][g]=tot++; fa[node[u][g]]=u; } u=node[u][g]; val[u]+=1; dp[u]=max(dp[u],c); }}int findf(int s){ int u=0,ans=-1,flag=0; for(int i=30;i>=0;i--) { int g=(s>>i)&1; int gg=(x>>i)&1; if(gg){ if(node[u][g]&&val[node[u][g]]) ans=max(ans,dp[node[u][g]]); if(node[u][g^1]&&val[node[u][g^1]]) g=g^1; } u=node[u][g]; if(!u||!val[u]) break; if(i==0) {flag=1;ans=max(ans,dp[u]);} } //if(flag) return ans; return ans;}void del(int s){ int u=0,flag=0; for(int i=30;i>=0;i--) { int g=(s>>i)&1; if(!node[u][g]) { flag=1;break; } } u=0; if(!flag) { for(int i=30;i>=0;i--) { int g=(s>>i)&1; val[node[u][g]]-=1; u=node[u][g]; } } if(!val[u]) { dp[u]=0; while(u) { u=fa[u]; dp[u]=0; if(node[u][0]&&val[node[u][0]]) dp[u]=dp[node[u][0]]; if(node[u][1]&&val[node[u][1]]) dp[u]=max(dp[u],dp[node[u][1]]); } }}int main(){ int T; scanf("%d",&T); while(T--) { tot=1; memset(node,0,sizeof(node)); memset(val,0,sizeof(val)); memset(dp,0,sizeof(dp)); memset(sum,0,sizeof(sum)); memset(a,0,sizeof(a)); memset(fa,0,sizeof(fa)); scanf("%d %d %d",&n,&x,&l); scanf("%I64d %I64d %I64d",&a[1],&p,&q); for(int i=2;i<=n;i++) a[i]=(a[i-1]*p%mod+q)%mod; for(int i=1;i<=n;i++) sum[i]=sum[i-1]^a[i]; sert(0,0); int ans=0; int c=0; for(int i=1;i<=n;i++) { if(i-l-1>=0) del(sum[i-l-1]); c=findf(sum[i])+1; if(c>0) sert(sum[i],c); } printf("%d\n",c); } return 0;}
- 字典树01
- 01字典树专题
- 01字典树 小结
- 01字典树模板
- hdu5296 01字典树
- 01字典树
- 01字典树
- 01字典树模板
- 01字典树板子
- 01字典树+贪心(顺便总结字典树模板)
- hdu 5269 01字典树
- hdu4825 01字典树+贪心
- hdu 4825 01字典树
- POJ 3764:01字典树
- HDU 4825 01字典树
- HDU 5536 01字典树
- HDU 6059 01字典树
- 字典树
- TFS安装与管理
- ios中UITextField的使用
- CSS垂直居中的11种实现方式
- hdoj2013_蟠桃记
- LBS 是什么服务?
- 01字典树
- C++数组长度
- Linux GCC常用命令
- 12-总结-【cartographer源码分析】系列的第一部分【common源码分析】
- PostgreSQL8.4 dblink使用
- My Debug 00
- 异常捕获
- HashData 数据仓库离线安装手册
- Linux中7个用来浏览网页和下载文件的命令分析