标签: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\)(也可以理解为是否有压着界)。
从上往下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;
}
标签:stdout 没有 main 固定 algo sizeof string algorithm mat
原文地址:https://www.cnblogs.com/jz-597/p/14083992.html