luogu P8019-OR-XOR

luogu P8019-OR-XOR

题目大意

有一个 \(n\) 个数的序列 \(a\) ,你需要将其分成 \(m\) 段,每一段内进行异或操作,段之间进行或操作。你要使得最后的结果最小。

\(Hint\)

把更高位的 \(1\) 消掉一定是赚的。

题解

对于一位二进制位来说,只有偶数个 \(1\) 才能使得这一位归零。

那么我们从高位到低位遍历,一位上有奇数个 \(1\) 就跳过这一位。有偶数个 \(1\) 时,我们将两两带有 \(1\) 的数字定为一个段的两端,将整个序列合并,如果合并后,段数小于 \(m\) ,则取消这次合并。

最后我们将序列剩下的数按位或即可。

#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define umap unordered_map
#define endl '\n'
using namespace std;
using i128 = __int128;
const int mod =1e9+7;
template <typename T>void read(T&x){
    x=0;int f = 1;
    char c=getchar();
    for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
    for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+(c^48);
    x*=f;
}
template <typename T>void print(T x) {
     if (x < 0) { putchar('-'); x = -x; }
     if (x > 9) print(x / 10);
     putchar(x % 10 + '0');
}
#define int long long
const int N=500005;
const int M=2000005;
inline void solve()
{
	int n,m;
	cin>>n>>m;
	vector<int> num(n),_num;
	for(int i=0;i<n;i++) cin>>num[i];
	for(int i=62;i>=0;i--)
	{
		_num.clear();
		int sum=0;
		for(int j=0;j<num.size();j++) if((num[j]>>i)&1) sum++;
		if(sum%2) continue;
		sum=0;
		int last=-1;
		for(int j=0;j<num.size();j++)
		{
			if((num[j]>>i)&1) 
			{
				sum++;
				if(sum%2==0)
				{
					int temp=0;
					for(int l=last;l<=j;l++)
					{
						temp^=num[l];
					}
					_num.push_back(temp);
				}
				else
				{
					last=j;
				}
			}
			else
			{
				if(sum%2==0) _num.push_back(num[j]);
			}
			
		}
		if(_num.size()>=m) num=_num;
	}
	int ans=0;
	for(int i=0;i<num.size();i++)
	{
		ans|=num[i];
	}
	cout<<ans<<endl;
}

signed main()
{
	ios;
	int T=1;
//	cin>>T;
	for(;T--;) solve();
	return 0;
}
posted @ 2025-11-18 20:04  NDAKJin  阅读(4)  评论(0)    收藏  举报