• 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
  • 相关阅读:
    POJ
    POJ-2253 Frogger(最短路)
    背包问题(转自背包九讲+对应题目)
    POJ-1860 Currency Exchange (最短路)
    Bellman-Ford 最短路径算法
    POJ-3295 Tautology (构造)
    POJ-2586 Y2K Accounting Bug 贪心
    POJ 2965 The Pilots Brothers' refrigerator (暴力枚举)
    python(pymysql操作数据库)
    python复习概念__oop中
  • 原文地址:https://www.cnblogs.com/ctyakwf/p/12433738.html
Copyright © 2020-2023  润新知