Codeforces Round 1004 (Div. 1) C. Bitwise Slides

Codeforces Round 1004 (Div. 1) C. Bitwise Slides

题意

  • 给你一个数组,三个整数P,Q,R​

  • 每一个操作使得P,Q,R三个数中的某个数异或s[i]

  • 每一步操作后需要保证三个数中至少两个数相同,问合法操作的种类数

思路:

首先考虑二维 d p dp dp,假设当前三个数为上一次操作后三个数为 i,i,j,那么 d p i , j dp_{i,j} dpi,j代表上次操作产生i,i,j​的种类数

假设当前的数为s[i]​,那么那么有以下转移方程:
d p [ 0 ] [ 0 ] × 3 → d p [ 0 ] [ s [ i ] ] d p [ i ] [ j ] → d p [ i ] [ j ⊕ s [ i ] ] if j ⊕ s [ i ] ≠ i d p [ i ] [ j ] × 2 → d p [ j ] [ i ] if j ⊕ s [ i ] = i \begin{aligned} dp[0][0] \times 3 &\rightarrow dp[0][s[i]] \\ dp[i][j] &\rightarrow dp[i][j \oplus s[i]] \quad \text{if} \ j \oplus s[i] \neq i \\ dp[i][j] \times 2 &\rightarrow dp[j][i] \quad \text{if} \ j \oplus s[i] = i \end{aligned} dp[0][0]×3dp[i][j]dp[i][j]×2→dp[0][s[i]]→dp[i][j⊕s[i]]if j⊕s[i]=i→dp[j][i]if j⊕s[i]=i

我们发现,只记录 y = i ⊕ j y=i \oplus j y=i⊕j可以使得
d p ′ [ y ] = ∑ i = j ⊕ y d p [ i ] [ j ] dp^{'}[y]=\sum _{i=j \oplus y} dp[i][j] dp′[y]=i=j⊕y∑dp[i][j]

这样,转移方程变为:
d p [ 0 ] × 3 → d p [ s [ i ] ] d p [ s [ i ] ] → 2 × d p [ s [ i ] ] d p [ i ] → d p [ i ⊕ s [ i ] ] for all i \begin{aligned} dp[0] \times 3 &\rightarrow dp[s[i]] \\ dp[s[i]] &\rightarrow 2 \times dp[s[i]] \\ dp[i] &\rightarrow dp[i \oplus s[i]] \quad \text{for all} \ i \end{aligned} dp[0]×3dp[s[i]]dp[i]→dp[s[i]]→2×dp[s[i]]→dp[i⊕s[i]]for all i

由此我们可以写出以下代码:

cpp 复制代码
		map<int, int> dp;
        dp[s[0]] = 3;
        for (int i = 1; i < n; i++)
        {
            map<int, int> tem;
            for (auto j : dp)
            {
                if (j.first == s[i])
                    tem[s[i]] = (tem[s[i]] + (dp[j.first] * 2) % mod) % mod;
                if (j.first != 0)
                    tem[j.first ^ s[i]] = (tem[j.first ^ s[i]] + dp[j.first]) % mod;
                else
                    tem[j.first ^ s[i]] = (tem[j.first ^ s[i]] + (dp[j.first] * 3) % mod) % mod;
            }
            dp = tem;
        }

我们发现设置一个tag能将所有 d p [ x ] dp[x] dp[x] 整体变为 d p [ x ⊕ s [ i ] ] dp[x \oplus s[i]] dp[x⊕s[i]],于是有了以下优化

cpp 复制代码
		map<int, int> dp;
        dp[s[0]] = 3;
        for (int i = 1; i < n; i++)
            dp[now] = (dp[now] * 3) % mod, dp[now] = (dp[now] + (dp[now ^ s[i]] * 2) % mod) % mod, now ^= s[i];

从左到右枚举所有数后 ,答案为 ∑ d p [ i ] \sum dp[i] ∑dp[i]

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
#define int long long int
#define Paddi ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
const int mod = 1e9 + 7;
signed main()
{
    Paddi;
    int T;
    cin >> T;
    while (T--)
    {
        int n;
        cin >> n;
        vector<int> s(n);
        for (int i = 0; i < n; i++)
            cin >> s[i];
        int ans = 0;
        int now = 0;
        map<int, int> dp;
        dp[s[0]] = 3;
        for (int i = 1; i < n; i++)
            dp[now] = (dp[now] * 3) % mod, dp[now] = (dp[now] + (dp[now ^ s[i]] * 2) % mod) % mod, now ^= s[i];
        for (auto i : dp)
            ans = (ans + i.second) % mod;
        cout << ans % mod << endl;
    }
    return 0;
}
相关推荐
小糯米6018 分钟前
C++顺序表和vector
开发语言·c++·算法
独望漫天星辰18 分钟前
C++ 多态深度解析:从语法规则到底层实现(附实战验证代码)
开发语言·c++
We་ct28 分钟前
LeetCode 56. 合并区间:区间重叠问题的核心解法与代码解析
前端·算法·leetcode·typescript
Lionel68933 分钟前
分步实现 Flutter 鸿蒙轮播图核心功能(搜索框 + 指示灯)
算法·图搜索算法
小妖66637 分钟前
js 实现快速排序算法
数据结构·算法·排序算法
xsyaaaan39 分钟前
代码随想录Day30动态规划:背包问题二维_背包问题一维_416分割等和子集
算法·动态规划
王老师青少年编程1 小时前
2024年信奥赛C++提高组csp-s初赛真题及答案解析(阅读程序第3题)
c++·题解·真题·csp·信奥赛·csp-s·提高组
凡人叶枫2 小时前
C++中输入、输出和文件操作详解(Linux实战版)| 从基础到项目落地,避坑指南
linux·服务器·c语言·开发语言·c++
CSDN_RTKLIB2 小时前
使用三方库头文件未使用导出符号情景
c++
zheyutao2 小时前
字符串哈希
算法