HDU5715 XOR游戏(二分+Trie)

一遇到异或前缀和以及最大,一定要想Trie树,因为这是经典做法,通过贪心来找

本题可以二分异或值,来进行判定,这题我学了一下trie用结构体的模板

#include<iostream>
#include<vector>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<queue>
#include<map>
#include<cstring>
#include<string>
using namespace std;
typedef long  long ll;
const int N=1e5+10;
int n,m,l;
int cnt[12];
int f[N][110];
int a[N];
struct node{  //多个trie树模板
    int num[2];
    int sum;
    void init(){
        num[0]=num[1]=sum=0;
    }
}tr[12][N];
void add(int p,int x,int sign){
    int cur=1;
    tr[p][cur].sum+=sign;
    for(int i=30;i>=0;i--){
        int y = x>>i&1;
        if(!tr[p][cur].num[y])
            tr[p][cur].num[y]=++cnt[p];
        cur=tr[p][cur].num[y];
        tr[p][cur].sum+=sign;
    }
}
int find(int p,int x){//异或的经典操作,通过贪心在trie树上找相反求最大
    int cur=1,ans=0;
    for(int i=30;i>=0;i--){
        int y=x>>i&1;
        if(tr[p][tr[p][cur].num[y^1]].sum)
            ans+=1<<i,cur=tr[p][cur].num[y^1];
        else
            cur=tr[p][cur].num[y];
    }
    return ans;
}
int check(int mid){
    for(int i=0;i<=m+1;i++)//初始化不要用memset,容易超时,很难查错
        for(int j=1;j<=cnt[i];j++)
            tr[i][j].init();
    for(int i=0;i<=m+1;i++)
        cnt[i]=1;
    for(int i=0;i<=n;i++)
        for(int j=0;j<=m;j++)
        f[i][j]=0;
    f[0][0]=1;//只有这种状态是初始合法的,也就是前0个分成0组
    add(0,0,1);//刚开始是只有0这个数
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(i>l&&f[i-l-1][j-1]) //当前位置已经超过l长度了,说明不能更新,如果前面是合法转移,要从trie树中删掉
                add(j-1,a[i-l-1],-1);
            int tmp=find(j-1,a[i]);
            if(tmp>=mid){
                add(j,a[i],1);
                f[i][j]=1;
            }
        }
    }
    return f[n][m];
}
int main(){
    int t;
    cin>>t;
    int cnt=1;
    while(t--){
       cin>>n>>m>>l;
       int i;
       memset(tr,0,sizeof tr);
       for(i=1;i<=n;i++){
        scanf("%d",&a[i]);
        a[i]^=a[i-1];
       }
       int l=0,r=0x3f3f3f3f;
       while(l<r){
         int mid=l+r+1>>1;
         if(check(mid))
            l=mid;
         else
            r=mid-1;
       }
       printf("Case #%d:
",cnt++);
       cout<<l<<endl;
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/ctyakwf/p/12433738.html