CF1582F2 Korney Korneevich and XOR 题解

思路

dp 然后优化。

dpi,j=0/1dp_{i,j}=0/1 表示是否有末尾数 <i<i,异或和为 jj 的子序列。对于具体的数,其实不用关心。

假设现在处理 aia_i,枚举异或和 jj,那么所有 dpk,jxoraiai<k<V,dpj=1dp_{k,j} \operatorname{xor} a_i|a_i<k<V,dp_j=1 都会被更新。

下面优化:

  • 对于相同的异或和,如果 fi,jf_{i,j} 已经被更新,那么 fi+1V,jf_{i+1 \sim V,j} 都被更新了,我们设立数组 MiM_i 为需要枚举到 MiM_{i}Mi+1VM_{i+1}\sim V 无需枚举。

  • 第二维的枚举太慢了,假如都是每个状态都是 00,就浪费时间。可以设一个 fi,jf_{i,j},记录异或和为 ii 时要枚举哪些 jj 值。更新完就全部删除。(类似 spfa)


代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10,M = 8192;
int n,v[M],m[M],ans=1;
vector<int>b[M];//每个<ai要枚举哪些 
int main() {
	cin>>n;
	v[0]=1;
	for(int i=1;i<=M-1;i++) {
		m[i]=M-1;b[i].push_back(0);
	}
	for(int i=1,t;i<=n;i++) {
		cin>>t;
		for(int j:b[t]) {
			int k=t^j;
			if(v[k]==0) ans++;
			v[k]=1;
			while(m[k]>t) b[m[k]--].push_back(k);
		}
		b[t].clear();
		b[t].push_back(0);
	}
	cout<<ans<<endl;
	for(int i=0;i<M;i++) if(v[i]) cout<<i<<" ";
	return 0;
}
posted @ 2023-11-09 09:37  cjrqwq  阅读(11)  评论(0)    收藏  举报  来源