HDU5715 XOR 游戏 二分+字典树+dp
Posted shuguangzw
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU5715 XOR 游戏 二分+字典树+dp相关的知识,希望对你有一定的参考价值。
当时Astar复赛的时候只做出1题,赛后补题(很长时间后才补,懒真是要命),发现这是第二简单的
分析:
这个题,可以每次二分区间的最小异或和
进行check的时候用dp进行判断,dp[i][j]代表前i个元素分成j个区间,j是最后一个区间的最后一个元素
如果dp[i][j]为真,表明每个区间长度大于L,异或和大于mid
否则为假
返回dp[n][m]就好
复杂度度 O(30^2*nm)
吐槽:和异或相关的题总是和字典树贪心有关,又是一道,铭记铭记
#include <stdio.h> #include <algorithm> #include <string.h> using namespace std; const int N = 1e4+5; typedef long long LL; int n,m,l,T,cas,tot; int a[N]; struct Node{ int sum,nex[2]; }p[N*35*12]; int newnode(){ ++tot; p[tot].sum=0;p[tot].nex[0]=p[tot].nex[1]=-1; return tot; } int root[12]; void add(int pos,int x){ int now=root[pos],cur; ++p[now].sum; for(int i=30;i>=0;--i){ if(x&(1<<i))cur=1; else cur=0; if(p[now].nex[cur]==-1) p[now].nex[cur]=newnode(); now=p[now].nex[cur]; ++p[now].sum; } } void del(int pos,int x){ int now=root[pos],cur; --p[now].sum; for(int i=30;i>=0;--i){ if(x&(1<<i))cur=1; else cur=0; now=p[now].nex[cur]; --p[now].sum; } } int query(int pos,int x){ int now=root[pos],ret=0,cur; if(p[now].sum==0)return 0; for(int i=30;i>=0;--i){ if(x&(1<<i))cur=1; else cur=0; if(p[now].nex[cur^1]!=-1&&p[p[now].nex[cur^1]].sum!=0){ ret+=(1<<i); now=p[now].nex[cur^1]; } else now=p[now].nex[cur]; } return ret; } bool dp[N][12]; bool check(int mid){ tot=0; for(int i=0;i<m;++i) root[i]=newnode(); for(int i=0;i<=n;++i) for(int j=0;j<=m;++j)dp[i][j]=false; dp[0][0]=true;add(0,0); for(int i=1;i<=n;++i){ if(i-l-1>=0){ for(int j=0;j<=m;++j) if(dp[i-l-1][j])del(j,a[i-l-1]); } for(int j=1;j<=m;++j){ int tmp=query(j-1,a[i]); if(tmp>=mid)add(j,a[i]),dp[i][j]=true; } } return dp[n][m]; } int main(){ scanf("%d",&T); while(T--){ scanf("%d%d%d",&n,&m,&l); for(int i=1;i<=n;++i) scanf("%d",&a[i]),a[i]^=a[i-1]; int l=0,r=1e9+7,ret; while(l<=r){ int mid=(l+r)>>1; if(check(mid))l=mid+1,ret=mid; else r=mid-1; } printf("Case #%d:\\n%d\\n",++cas,ret); } return 0; }
以上是关于HDU5715 XOR 游戏 二分+字典树+dp的主要内容,如果未能解决你的问题,请参考以下文章
UVALive 3942 Remember the Word 字典树+dp