码迷,mamicode.com
首页 > 其他好文 > 详细

CF1456E XOR-ranges

时间:2020-12-08 12:44:35      阅读:4      评论:0      收藏:0      [点我收藏+]

标签:stdout   没有   main   固定   algo   sizeof   string   algorithm   mat   

定义\(p(x)\)表示\(\sum_{i=0}^{k-1} bit(x,i)c_i\)。一个序列的贡献定义为\(\sum p(a_i\ xor \ a_{i+1})\)

给出\([l_i,r_i]\),构造一个序列满足\(a_i\in [l_i,r_i]\),求最大贡献。

\(n,k\le 50\)


%%%ll倒序开题爆切E。

为了方便把值域限制变成开区间。

定义\(keybit=highbit(l\ xor \ r)\),从高位往低位考虑,到\(keybit\)前,取值是固定的;到\(keybit\)会选择往左还是往右,接下来就只需要考虑\(l\)\(r\)的影响。设想有个\(Trie\),连出根到\(l\)\(r\)的链。对于一个\(x\in (l,r)\),它的取值范围相当于左右链分叉后,左链向左时的右子树和右链向右时的左子树。(如果直接看数字,相当于:在某一位如果没有压着界,后面的就可以任意选)

现在考虑第\(i\)位和序列上的区间\((L,R)\),如果\(L\)\(R\)\(i\)位被固定,而\((L,R)\)可以任意选,当前局面的贡献肯定是\((bit(L,i)\ xor \ bit(R))*c_i\)。题解称这样的区间visible。

现在设想一个算法,从\(i=0,L=0,R=n+1\)开始。对于一个询问\(query(i,L,R,\dots)\),决策时钦定\(x_0,x_1,\dots,x_k\)\(x_0=L,x_k=R\)),让\(bit(a_{x_j},i)\)被固定,其它在第\(i\)位都没有被固定,那么贡献为\(\sum query(i+1,x_j,x_{j+1},\dots)+cost(\dots)\)。递归下去做。

结合前面的分析搞个DP:\(f_{i,L,R,sL,sR}\),后面\(sL\)为二元组\((d,w)\)表示\(L\)的状态,\(d\)表示\(L\)\(keybit_L\)时选了哪边,\(w\)表示\(L\)最小的被固定的位置是否为\(i\)(也可以理解为是否有压着界)。

  1. 如果\((L,R)\)都可能在\(i\)位任意选(即\((L,R)\)可以visible),可以\(f_{i+1,L,R,(sL.d,0),(sR.d,0)}+cost(\dots)\to f_{i,L,R,sL,sR}\)
  2. \((L,R)\)拆开。枚举其中一个分界点\(md\)\(f_{i,L,md,sL,(0/1,1)}+f_{i,md,R,(0/1,1),sR}\to f_{i,L,R,sL,sR}\)

从上往下DP即可。\(i=k\)时显然合法当且仅当\(L+1=R\)

注意各种细节。


using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 57
#define ll long long
#define INF 0x3f3f3f3f3f3f3f3f
int n,k;
ll lim[N][2];
int lg(ll x){
	ll c=0;
	for (;x;x>>=1)
		++c;
	return c;
}
int kb[N];
ll c[N];
ll f[N][N][N][4][4];//(0/1,0/1) keybit , if equal to i 
void tran(ll &x,ll y){x>y?x=y:0;}
bool judge(int l,int r,int i){
	for (int md=l+1;md<=r-1;++md)
		if (i>=kb[md]-1)
			return 0;
	return 1;
}
int main(){
//	printf("%lld\n",sizeof(f));
//	return 0;
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	scanf("%d%d",&n,&k);
	for (int i=1;i<=n;++i){
		scanf("%lld%lld",&lim[i][0],&lim[i][1]);
		lim[i][0]+=1ll<<k,lim[i][1]+=1ll<<k;
		lim[i][0]--,lim[i][1]++;
		kb[i]=lg(lim[i][0]^lim[i][1])-1;
	}
	lim[0][0]=lim[1][0],lim[0][1]=lim[1][1],kb[0]=kb[1];
	lim[n+1][0]=lim[n][0],lim[n+1][1]=lim[n][1],kb[n+1]=kb[n];
	for (int i=0;i<k;++i)
		scanf("%lld",&c[i]);
	k+=2;
//	kb[0]=kb[n+1]=k-1;
//	lim[0][0]=0,lim[0][1]=(1ll<<k)-1;
//	lim[n+1][0]=0,lim[n+1][1]=(1ll<<k)-1;
	memset(f,63,sizeof f);
	for (int l=0,r;l<=n+1;++l){
		r=l+1;
		for (int sl=0;sl<2;++sl)
			for (int sr=0;sr<2;++sr)
				f[k][l][r][sl][sr]=0;
	}
	for (int i=k-1;i>=0;--i){
		for (int l=n+1;l>=0;--l)
			for (int r=l+1;r<=n+1;++r){
				for (int sl=0;sl<4;++sl)
					for (int sr=0;sr<4;++sr){
						if (sl>>1 && !(i<kb[l] && (lim[l][sl&1]>>i&1)==(sl&1)))
							continue;
						if (sr>>1 && !(i<kb[r] && (lim[r][sr&1]>>i&1)==(sr&1)))
							continue;
						if (judge(l,r,i))
							tran(f[i][l][r][sl][sr],f[i+1][l][r][sl&1][sr&1]+(1<=l && r<=n?((lim[l][sl&1]>>i&1^sl>>1)^(lim[r][sr&1]>>i&1^sr>>1))*c[i]:0));
						for (int md=l+1;md<=r-1;++md){
							tran(f[i][l][r][sl][sr],f[i][l][md][sl][2]+f[i][md][r][2][sr]);
							tran(f[i][l][r][sl][sr],f[i][l][md][sl][3]+f[i][md][r][3][sr]);
						}
					}
			}
	}
	ll ans=INF;
	for (int sl=0;sl<4;++sl)
		for (int sr=0;sr<4;++sr)
			ans=min(ans,f[0][0][n+1][sl][sr]);
	printf("%lld\n",ans);
	return 0;
}

CF1456E XOR-ranges

标签:stdout   没有   main   固定   algo   sizeof   string   algorithm   mat   

原文地址:https://www.cnblogs.com/jz-597/p/14083992.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!