2020ICPC 江西省大学生程序设计竞赛 E.Color Sequence 二进制 异或位运算 传递1 思维

14 篇文章 1 订阅

题目

给你长度为N的序列,序列里的数只包含0到20。表示第i个位置的颜色。
要求计算出满足要求的子序列总数

子序列的含有的每个颜色数的总和都是偶数。

题解思路

比赛的时候想着什么暴力双指针一条路走到黑都没写出来。

这里颜色数很少,所以我们可以直接用21位的二进制数表示出来。
即0表示含偶数或者0个,1表示奇数个。
这样我们就能表示1到n的所有状态了。
用异或运算传递一下之前状态的结果。
再判断这个状态的是否含奇数个这个颜色。
如果是就变成这个位数就0,减去对应的幂次。
不是就加上对应的幂次。

这样我们就好像得出了每个位置的每种颜色的前缀和。

答案的获取。
我们要获取的是状态里只有0的数,这样答案只有两种来源。
之前的和这个状态相等的数,他们相减就可以得出这个区间为0。
还有一种是本身为0的情况。这种是从起点开始延申到这个位置的。直接加起来即可。

思路就是利用二进制来表示每个位置的每种颜色的状态。
挺难想到的。
以后看到种类少的优先进行二进制表示状态。

AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
#include <map>
#include <string>
#include <unordered_map>
using namespace std;

const  int  INF =  0x3f3f3f3f;

int f[1000100] ;
int a[1000100] ;
int mi[30] ;


int main ()
{
    ios::sync_with_stdio(false);cin.tie(0);
    unordered_map < int , int > mp  ;
    mi[1] = 1 ;
    long long ans = 0 ;
    for ( int i = 2 ; i <= 21 ; i++ )
        mi[i] = mi[i-1]*2 ;
    int n ;
    cin >> n ;
    f[0] = 0 ;
    for ( int i = 1 ; i <= n ; i++ )
    {
        int t1 ;
        cin >> t1 ;
        a[i] = t1 ;
        f[i] ^= f[i-1] ;
        if ( f[i] >> (t1) & 1 )
            f[i] -= mi[t1+1] ;
        else
            f[i] += mi[t1+1] ;
        ans += mp[f[i]] ;
        mp[f[i]]++ ;
      //  cout << f[i] << "\n" ;
    }
    cout << ans  + mp[0] << "\n" ;

    return 0 ;
    
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值