题解:P13687 【MX-X16-T5】「DLESS-3」XOR and Rockets
记
我们分两种情况讨论,最后一个数操作和不操作。
不操作
不操作的话整个序列的值域不超过
操作
我们称区间
我们用操作点将整个序列分为若干部分,显然这些部分都需要的好的,记他们分别是
我们记
也就是说,经过这样的转化后,每个部分都独立了。
于是问题就转移到了,如何在可接受的时间复杂度内求出每一个区间
对于一个区间内的相邻点
也就是说,如果
核心代码:
const int N=5010,V=8192,inf=1e17;
int n;
int a[N],b[N];
int f[N];
bool can[N][N];
signed nd[N][N];
int dp[N][V],pre[V],suf[V];
void solve()
{
n=R;
fo(i,1,n) a[i]=R;
fo(i,1,n) b[i]=R;
fo(i,1,n) fo(j,1,n) can[i][j]=0,nd[i][j]=0;
fo(i,1,n) f[i]=inf;
f[0]=0;
fo(i,1,n)
{
can[i][i]=1,nd[i][i]=0;
int nd0[13]={0},nd1[13]={0};
m1(nd0,0),m1(nd1,0);
fo(j,i+1,n)
{
if(a[j]>a[j-1])
{
rep(k,12,0) if((a[j]>>k&1)!=(a[j-1]>>k&1)){nd0[k]=1;break;}
}
if(a[j]<a[j-1])
{
rep(k,12,0) if((a[j]>>k&1)!=(a[j-1]>>k&1)){nd1[k]=1;break;}
}
bool flag=1;
fo(k,0,12) flag&=(nd0[k]==0||nd1[k]==0);
if(!flag) break;
can[i][j]=1;
fo(k,0,12) if(nd1[k]) nd[i][j]+=(1<<k);
// cout<<i<<' '<<j<<' '<<nd[i][j]<<endl;
}
}
fo(i,1,n) fo(j,0,i-1) if(can[j+1][i])
{
f[i]=min(f[i],f[j]+b[i]);
}
int ans1=f[n];
fo(i,1,n) fo(j,0,V-1) dp[i][j]=1e17;
fo(j,0,V-1) dp[n][j^a[n]]=(j!=0)*b[n];
// cout<<dp[n][0]<<endl;
rep(i,n,1)
{
if(i!=n)
{
fo(j,0,V-1)
{
int val=(a[i]^j^a[i+1]);
fo(k,val,val) if(j<=k) dp[i][j]=min(dp[i][j],dp[i+1][k]);
dp[i][j]=min(dp[i][j],suf[j]+b[i]);
}
}
pre[0]=dp[i][0];
fo(j,1,V-1) pre[j]=min(pre[j-1],dp[i][j]);
suf[V-1]=dp[i][V-1];
rep(j,V-2,0) suf[j]=min(suf[j+1],dp[i][j]);
}
int ans=1e17;
fo(i,0,V-1) ans=min(ans,dp[1][i]);
write(min(ans1,ans)),puts("");
}
void main(){
MT solve();
}