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;
}

浙公网安备 33010602011771号