- 给你一个序列,每次可以选择一个数xxx,将[l,r][l,r][l,r]段内所有数异或上xxx,花费⌈r−l+12⌉\lceil \frac{r-l+1}2{}\rceil⌈2r−l+1⌉,问最少花费多少能够让整个序列都变成0
- 可以发现在区间上处理不会优于区间内部
- 根据异或性质,x⨁x⨁x=xx\bigoplus x\bigoplus x=xx⨁x⨁x=x,我们可以枚举两个区间端点i,j,0≤j<ii,j,0\leq j<ii,j,0≤j<i,如果pre[i]⨁pre[j]=0pre[i]\bigoplus pre[j]=0pre[i]⨁pre[j]=0,那么说明[j+1,i][j+1,i][j+1,i]区间可以在前面基础上再i−j−1i-j-1i−j−1次异或全部成为0.(i−j−1+1−1)(i-j-1+1-1)(i−j−1+1−1)
- 设f[i]f[i]f[i]表示前iii个数处理的最少次数,那么我们能够写出O(n2)O(n^2)O(n2)的代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--){
int n;
cin >> n;
vector<int> a(n + 1), pre(n + 1);
vector<int> f(n + 1);
for(int i=1;i<=n;i++){
cin >> a[i];
pre[i] = pre[i - 1] ^ a[i];
}
for(int i=1;i<=n;i++){
f[i] = f[i - 1] + 1;
for(int j=0;j<i;j++){
if(pre[i] == pre[j]){
f[i] = min(f[i], f[j] + i - j - 1);
}
}
}
cout << f[n] << '\n';
}
return 0;
}
- 考虑优化,里面的循环是在寻找上一个异或和等于当前的位置,这个可以记录下来
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--){
int n;
cin >> n;
vector<int> a(n + 1), pre(n + 1);
vector<int> f(n + 1);
for(int i=1;i<=n;i++){
cin >> a[i];
pre[i] = pre[i - 1] ^ a[i];
}
map<int, pair<int, int> > mp;
mp[0] = {0, 0};
for(int i=1;i<=n;i++){
f[i] = f[i - 1] + 1;
if(mp.count(pre[i])){
f[i] = min(f[i], mp[pre[i]].first + i - mp[pre[i]].second - 1);
if(mp[pre[i]].first > f[i]){
mp[pre[i]] = {f[i], i};
}
}
mp[pre[i]] = {f[i], i};
}
cout << f[n] << '\n';
}
return 0;
}