zoukankan      html  css  js  c++  java
  • 异或维护奇偶性

    最近一下碰见两道思路一样的题目,我觉得有必要记录一下这两道题目的解法。

    第一道:牛客2020寒假集训题day4子段异或

    题目大意:输入一个数列a,你需要输出其中异或值为0的不同子段的数量。

    第二道:计蒜客CTU Open Contest 2019 G

    题目大意:给定一个字符串 s ,从中选定一个最长的子串,使得该子串的字符通过重新组合(任意顺序)可以成为一个回文串,输出这个子串的长度。

    这两道乍一看好像关系不大,但是其实它们的解法真的算是大同小异。

    首先我们要知道异或值为0是什么意思,异或值为0,通常说明对于一个数列里面所有不同数的数量都是偶数。

    这就产生了一个比较有用的应用,判断哪个数只出现一次。有兴趣的话看一下leetcode的Single number那题

    如果出现一次,那么异或值为它本身;两次,就自身异或变为0。(奇偶性)

    回到前面说的两道题目。

    这两道题基本上都要用到异或前缀的思想,可能第一题比较直接,第二题比较隐晦。

    由于奇偶性可以用异或表示,区间L,R的奇偶性等于区间1,R异或区间1-(L-1)。 

    所以这是个经典的解法:枚举以R为区间右端点,先求出1-R中间数据的奇偶关系,顺便记录每次情况出现的最早位置即L,如果当前情况有记录,即有最早出现的位置,则说明找到了一组情况。

    第一题就是这种做法。

    而第二题多了一个步骤,就是判断回文串是奇数个的情况。

    我们可以枚举每个字符,令这个字符是奇数,其他是偶数的最早出现的位置。

    如何记录字符出现情况?我们就用状态压缩的方法。

    #include <bits/stdc++.h>
    using namespace std;
    int n,x,i,j,vis[1<<21],ans;
    string s;
    int main()
    {
        cin>>n;
        getchar();
        getline(cin,s);
        memset(vis,-1,sizeof(vis));
        vis[0]=0;
        for (i=0,x=0;i<n;i++)
        {
            x^=(1<<(s[i]-97));
            if (vis[x]!=-1) ans=max(ans,i-vis[x]+1);
            for (j=0;j<21;j++)
            {
                int tmp=x^(1<<j);
                if (vis[tmp]!=-1) ans=max(ans,i-vis[tmp]+1);
            }
            if (vis[x]==-1) vis[x]=i+1;
        }
        cout<<ans<<endl;
        return 0;
    }
    第二题

    其实奇偶性本身就能出很多题目,异或这个神奇操作也是,所以做题目还是得学会变通才行啊。

  • 相关阅读:
    浙江大学数据结构:02-线性结构3 Reversing Linked List (25分)
    浙江大学数据结构:02-线性结构2 一元多项式的乘法与加法运算 (20分)
    浙江大学数据结构:01-复杂度2 Maximum Subsequence Sum (25分)
    SQL事务--转载
    触发器--转载
    项目版本控制工具SVN介绍--转载
    项目版本控制工具VSS介绍--转载
    AE开发中ICircularArc接口的图形要素保存与形状简化--原创
    ArcGISEngine绘制椭圆--转载
    NPOI学习--转载
  • 原文地址:https://www.cnblogs.com/Y-Knightqin/p/12375077.html
Copyright © 2011-2022 走看看