题解:AT_agc071_a [AGC071A] XOR Cross Over
半年前做过它,当时不会,由于在学文化也没学,今天晚自习自己做出来了。
首先设
容易发现,
打表代码:
#include <bits/stdc++.h>
using namespace std;
const int N=15;
bitset<N> a[N];
int n,v[N],p[N],fl[N];
void dfs(int x){
if(x==n){
for(int i=1;i<=n;i++) a[i]=0,a[i][i]=1;
for(int i=1;i<=n;i++) fl[i]=0;
fl[0]=fl[n]=1;
for(int i=1;i<n;i++){
bitset<N> al=0,ar=0;
for(int j=p[i];!fl[j];j--) al^=a[j];
for(int j=p[i]+1;;j++){ar^=a[j];if(fl[j]) break;}
for(int j=p[i];!fl[j];j--) a[j]^=ar;
for(int j=p[i]+1;;j++){a[j]^=al;if(fl[j]) break;}
fl[p[i]]=1;
}
cout<<"dfs::\n";
for(int i=1;i<n;i++) cout<<p[i]<<' '; cout<<'\n';
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++) cout<<a[i][j];
cout<<'\n';
}
return ;
}
for(int j=1;j<n;j++) if(!v[j]){
v[j]=1; p[x]=j;
dfs(x+1);
v[j]=0;
}
}
int main(){
ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
n=8;
dfs(1);
cerr<<1.0*clock()/CLOCKS_PER_SEC<<'\n';
return 0;
}
下文称偶数区间是长度为偶数的区间,奇数区间是长度为奇数的区间。
我们可以发现很多事情:
1.对
2.对于偶数的
这告诉我们做操作做到一个偶数区间时,我们不关心这个区间外面对里面的贡献,因为一个里面的位置都会把外面的贡献异或偶数次。
3.对于奇数的
我们设这个位置是
4.对于奇数的
5.对于奇数的
6.对于奇数的
根据发现的性质 4,5,6 我们猜测,答案就是
这个时候我们再来看
若下一次操作把他划分成两个偶数区间,由于我们已经推导出了“偶数区间不关心外面对里面的贡献”这件事,所以可以直接划分成两个独立的子问题。
若下一次操作把他划分成两个奇数区间,根据性质 3,我们只关心贡献对
然后我们就可以 dp 了:设
时间复杂度
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=505;
const LL linf=1e16+10;
int n;
LL a[N],f[N][N],g[N][N];
void read(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
a[i]^=a[i-1];
}
}
void dp(){
for(int i=1;i<=n;i++) for(int l=1;l+i-1<=n;l++){
int r=l+i-1;
f[l][r]=linf;
if(i&1){
for(int k=l;k<=r;k+=2){
f[l][r]=min(f[l][r],f[l][k-1]+f[k+1][r]+(a[r]^a[l-1]));
}
}else{
for(int k=l+1;k<r;k+=2){
f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]);
}
for(int k=l;k<=r;k+=2){
f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]-(a[k]^a[l-1])-(a[r]^a[k])+(a[r]^a[l-1])*2);
}
}
}
cout<<f[1][n]<<'\n';
}
int main(){
ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
read();
dp();
cerr<<1.0*clock()/CLOCKS_PER_SEC<<'\n';
return 0;
}
半年前那个还在迷茫徘徊的少年,我替你做出这道题了,你还满意吗?