zoukankan      html  css  js  c++  java
  • 1054D Changing Array 【位运算+思维】

    题目:戳这里

    题意:两个数n,k,满足给的n个数小于2的k次方。每个数可以进行一次操作,即把a[i]换成a[i]^(1<<k-1);求最多的连续区间数使得 区间[L,R] (1<=L<=R<=n),满足: a[L] ^ a[L+1] ^ … ^ a[R-1] ^ a[R] != 0

    解题思路:

    首先我们知道n个数可构成的连续区间是n*(n+1)/2个,如果一个一个找肯定会超时,需要一种能快速算出[L,R]区间异或和的方法。因为异或满足交换法则。所以a[1]^a[2]^...^a[L-1] ^ a[1]^a[2]^...^a[R]=a[L]^a[L+1]^...^a[R];也就是只要纪录前缀异或和,就可以快速算出每个区间的异或值。

    设前缀异或和为s[],maxx=1<<k-1。

    因为相等的值相互异或为0,所以只要s[L]==s[R],则[L,R]区间的异或和为0. 此外,假设对a[i]进行一次异或操作得a[i]'=a[i]^maxx,则s[i]'=s[i]^maxx,因为异或满足s[i]^maxx^maxx=s[i],所以对于s[]数组,每进行两次^maxx的操作,当前的前缀值s[i]就相当于没有进行操作。

    这样问题就转化为,经过无数次操作后,使得s[]数组中相等的数尽量的少,就可以用贪心解决了。

    用map<ll,ll>mp维护每个值出现的次数。计算前缀和s[i]值时,决策s[i]=mp[s[i-1]]>mp[s[i-1]^maxx]?s[i-1]^maxx:mp[s[i-1]];用基础的组合知识(确定L,R两端点便可以确定一个区间)就可以算出最终答案。

    附ac代码:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int maxn = 2e5 + 10;
     5 const ll mod = 998244353;
     6 ll a[maxn];
     7 int main() {
     8 
     9     ll n, k;
    10     scanf("%lld %lld", &n, &k);
    11     for(int i = 1; i <= n; ++i) {
    12         scanf("%lld", &a[i]);
    13     }
    14     ll ans = ll((n + 1) * n / 2);
    15     ll maxx = 1ll;
    16     maxx = (maxx << k) - 1ll;
    17     map<ll,ll> mp;
    18     mp[0] = 1;
    19     ll now = 0;
    20     for(ll i = 1; i <= n; ++i) {
    21         now ^= a[i];
    22         now = mp[now]>mp[now ^ maxx]?now^maxx:now;
    23         ans -= mp[now];//组合数Cn2
    24         mp[now]++;
    25     }
    26     printf("%lld
    ", ans);
    27     return 0;
    28 }
    View Code
  • 相关阅读:
    如何通过logcat查看系统程序的意图
    jmeter测试本地myeclips调试状态下的tomcat程序死锁
    利用开源项目使discus论坛与java应用同步登录和注册
    hibernate映射文件基础
    长沙理工大学校园网客户端无法卸载解决办法
    26个Jquery使用小技巧
    eclipse 书签
    Notepad++ 书签
    【转】不提拔你,就因为你只想把工作做好
    自己开发开源jquery插件--给jquery.treeview加上checkbox
  • 原文地址:https://www.cnblogs.com/zmin/p/9909695.html
Copyright © 2011-2022 走看看