CF2066C Bitwise Slides

Problem

题目描述

给定一个数组 \(a_1, a_2, \ldots, a_n\),以及三个初始值为零的变量 \(P, Q, R\)

你需要按从 \(1\)\(n\) 的顺序依次处理所有数字 \(a_1, a_2, \ldots, a_n\)。当处理当前元素 \(a_i\) 时,你必须从以下三个操作中任选一个执行:

  1. \(P := P \oplus a_i\)
  2. \(Q := Q \oplus a_i\)
  3. \(R := R \oplus a_i\)

其中 \(\oplus\) 表示按位异或操作。

执行操作时必须遵守核心规则:每次操作后,三个数 \(P, Q, R\) 必须满足其中至少存在两个数相等。

所有 \(n\) 个操作共有 \(3^n\) 种可能的执行方式。求其中不违反核心规则的方式数量。由于答案可能很大,请输出其对 \(10^9 + 7\) 取模的结果。

输入格式

每个测试包含多个测试用例。第一行输入测试用例数 \(t\)\(1 \le t \le 10^4\))。随后为各测试用例的描述。

每个测试用例的第一行包含一个整数 \(n\)\(1 \le n \le 2 \cdot 10^5\))——数组 \(a\) 的长度。

每个测试用例的第二行包含 \(n\) 个整数 \(a_1, a_2, \ldots, a_n\)\(1 \le a_i \le 10^9\))——数组 \(a\) 的元素。

保证所有测试用例的 \(n\) 之和不超过 \(2 \cdot 10^5\)

输出格式

对于每个测试用例,输出不违反核心规则的操作方式数量对 \(10^9 + 7\) 取模后的结果。

输入输出样例 #1

输入 #1

5
3
1 7 9
4
179 1 1 179
5
1 2 3 3 2
12
8 2 5 3 9 1 8 12 9 9 9 4
1
1000000000

输出 #1

3
9
39
123
3

说明/提示

第一个测试用例中,存在 3 种合法操作序列:PPP、QQQ、RRR。

第二个测试用例中,存在 9 种合法操作序列:PPPP、PPPQ、PPPR、QQQP、QQQQ、QQQR、RRRP、RRRQ、RRRR。

翻译由 DeepSeek R1 完成

Solution

已经到比较轻松的 DP 题。

\(dp_{i,x,y}\) 表示第 \(i\) 次操作后不同的数为 \(x\),两个相同的数为 \(y\) 的方案数。那么即有转移:

\[dp_{i,x,y}\to dp_{i+1,x\oplus a_{i+1},y} \]

\[2\times dp_{i,x,x\oplus a_{i+1}}\to dp_{i+1,x\oplus a_{i+1},x} \]

\[2\times dp_{i,x,x}\to dp_{i,x\oplus a_{i+1},x} \]

我们关注到,每次操作后,\(P\) \(Q\) \(R\) 三个数中一定有两个相等,所以三个数的异或和即为三个数中,与另外两个数不相等的那一个(如果三个数都相等即为任意一个),而三个数的异或和又等于前 \(i\) 个数的异或和,所以前 \(i\) 个数的异或和即为第 \(i\) 次操作后不同的那个数。所以每次操作后不同的那个数是一个定值,那么我们就可以将 dp 状态的第二维直接删去,再通过滚动数组将第一维删去,只留下最后一维。转移如下:

\[2\times (dp_{x\oplus a_{i+1}}+dp_{x})\to dp_x \]

我们关注到虽然每次操作后,\(x\) 的值域范围为 \(0\le x\le 10^9\),但是最多只有 \(n\) 种,所以我们采用动态开店线段树来节省空间(当然也可以使用 map)。

Code

#include<bits/stdc++.h>
#define int long long
#define N 200005
#define mod 1000000007
using namespace std;

int T,n,mx;
int a[N];

struct s_tree{
	int rt=0,idx=0;
	struct node{int ls,rs,sum;}t[N<<2];
	inline void add(int &id,int l,int r,int x,int val){
		if(!id)id=++idx;
		if(l==r){
			t[id].sum=(t[id].sum+val)%mod;
			return;
		}
		int mid=(l+r)>>1;
		if(x<=mid)add(t[id].ls,l,mid,x,val);
		else add(t[id].rs,mid+1,r,x,val);
		t[id].sum=(t[t[id].ls].sum+t[t[id].rs].sum)%mod;
	}
	inline int query(int id,int l,int r,int x){
		if(!id)return 0;
		if(l==r)return t[id].sum;
		int mid=(l+r)>>1;
		if(x<=mid)return query(t[id].ls,l,mid,x);
		else return query(t[id].rs,mid+1,r,x);
	}
	inline void clear(){
		for(int i=1;i<=idx;i++)t[i].ls=t[i].rs=t[i].sum=0;
		rt=idx=0;
	}
}tr;

signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>T;
	while(T--){
		tr.clear();
		cin>>n;
		mx=0;
		for(int i=1;i<=n;i++)cin>>a[i],mx=max(mx,a[i]);
		tr.add(tr.rt,0,(mx<<1),0,1);
		int s=0;
		for(int i=0;i<n;i++){
			int val=tr.query(tr.rt,0,(mx<<1),(s^a[i+1]))+tr.query(tr.rt,0,(mx<<1),s);
			tr.add(tr.rt,0,(mx<<1),s,2*val);
			(s^=a[i+1]);
		}
		cout<<tr.t[tr.rt].sum<<"\n";
	}
	return 0;
}
posted @ 2025-11-21 21:31  WDY_Hodur  阅读(0)  评论(0)    收藏  举报