zoukankan      html  css  js  c++  java
  • 【每日一题】36. 小AA的数列 (二进制DP)

    补题链接:Here

    算法涉及:位运算,DP

    这道题想了很久但实在没想什么巧妙的解法,暴力的代码就不放,这里引用Kur1su 的思路

    异或问题优先考虑二进制位,对于这个问题,我们需要考虑偶数长度的区间,那么先对 ([L, R]) 做处理,因为如果 (L,R) 是奇数其实加一/减一没有区别。然后处理一下前缀异或和, 因为我们有性质 (sum[l, r] = sum[r] oplus sum[l - 1])。最后我们要找到哪些是有贡献的,我们考虑枚举右端点,如果当前点的异或是 1,那么需要在前面找异或为 0 的点才有贡献,反之如果当前点的异或是 0,那么要在前面找异或为 1 的点才有贡献,此外,奇数下标要找奇数下标,偶数下标要找偶数下标,才能构成偶数长度区间。
     所以我们可以用 (dp[i][j]) 维护前面符合条件的状态数,第一维表示当前位为 (0/1,) 第二维表示当前下标为 奇/偶的状态数,直接计算贡献即可。

    using ll = long long;
    const int N = 1e6 + 10, mod = 1e9 + 7;
    
    int a[N];
    
    void solve() {
        int n, l, r; cin >> n >> l >> r;
        for (int i = 1; i <= n; ++i) {
            cin >> a[i];
            a[i] ^= a[i - 1];
        }
        if (l & 1) l++; // 保证区间为偶数长度
        if (r & 1) r--; // 保证区间为偶数长度
        if (l > r) { cout << 0; return ;}
        ll ans = 0;
        for (int i = 0; i < 32; ++i) { // 二进制运算
            ll p = (1ll << i);
            ll dp[2][2] = {0};
            ll num = 0;
            for (int j = l; j <= n; ++j) {
                dp[(a[j - l] >> i) & 1][(j - l) & 1]++;
                num += dp[((a[j] >> i) & 1) ^ 1][j & 1];
                num %= mod;
                if (j >= r)dp[(a[j - r] >> i) & 1][(j - r) & 1]--;
            }
            ans += num * p % mod;
            ans %= mod;
        }
        cout << ans;
    }
    

    The desire of his soul is the prophecy of his fate
    你灵魂的欲望,是你命运的先知。

  • 相关阅读:
    less的一些用法整理
    flex 布局下关于容器内成员 flex属性的理解
    Web开发者需具备的8个好习惯
    GridView分页功能的实现
    程序员长期保持身心健康的几点建议
    程序员必知的10大基础实用算法
    结对编程
    Python_Day_02 str内部方法总结
    Python_Day_01(使用环境为Python3.0+)
    圆形头像制作
  • 原文地址:https://www.cnblogs.com/RioTian/p/14814994.html
Copyright © 2011-2022 走看看