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:
%d
",++cas,ret);
  }
  return 0;
}
View Code
原文地址:https://www.cnblogs.com/shuguangzw/p/5636012.html