BZOJ4676 Xor-Mul棋盘
题目大意懒得写了,题目说的挺明白的了
题解
主要的难点在于异或意义下的最大值和很玄学,但不难发现这道题中让你定义的$D_{i,j}$只参与异或运算,所以我们可以逐位进行讨论。所以我们每一位就只有$0$和$1$两种状态,由于$n$很小,所以我们可以把每一列的$01$情况压成二进制状态。由于是在异或意义下,我们可以预处理这一位上每一列每个状态的$A$的$01$情况,每一列的每一个状态的$\sum B_{i,j}$和每两列之间每个状态的比边权和,以及每一列每个状态纵向的边的贡献,直接从左向右递推即可,转移时通过异或运算直接计算出转移时新产生的增量。
复杂度$O(2^{2n}m\log_2 10^6+2^nnm)$
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #define LL long long #define M 20020 #define INF 2000000000000000000ll using namespace std; int read(){ int nm=0,fh=1; int cw=getchar(); for(;!isdigit(cw);cw=getchar()) if(cw=='-') fh=-fh; for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0'); return nm*fh; } int n,m,A[6][M],B[6][M],E[6][M],V[6][M],K[M][40]; int val[M][40],G[M][40],S[M],len[M],MAXN; LL F[M][40],ans; void init(int x,int now,int sta,int cst){ if(now==n){G[x][sta]=cst;return;} init(x,now+1,sta,cst); init(x,now+1,sta|(1<<now),cst+E[now][x]); } void dfs(int x,int now,int sta,int cst){ if(now==n){val[x][sta]=cst;return;} dfs(x,now+1,sta,cst); dfs(x,now+1,sta|(1<<now),cst+B[now][x]); } int main(){ n=read(),m=read(),memset(F,0x3f,sizeof(F)),MAXN=(1<<n); for(int i=0;i<n;i++) for(int j=1;j<=m;j++) A[i][j]=read(); for(int i=0;i<n;i++) for(int j=1;j<=m;j++) B[i][j]=read(); for(int i=0;i<n;i++) for(int j=1;j<m;j++) E[i][j]=read(); for(int i=0;i<n-1;i++) for(int j=1;j<=m;j++) V[i][j]=read(); for(int i=1;i<=m;i++){ if(i<m) init(i,0,0,0); dfs(i,0,0,0),len[i]=read(); for(int ss=0;ss<MAXN;ss++){ for(int j=0;j<n-1;j++) K[i][ss]+=(((ss>>j)^(ss>>(j+1)))&1)*V[j][i]; if((ss^(ss>>(n-1)))&1) K[i][ss]+=len[i]; } } for(int k=0;k<21;k++){ int ct=0; memset(S,0,sizeof(int)*(m+1)); for(int i=1;i<=m;i++){ for(int j=0;j<n;j++) S[i]|=(((A[j][i]>>k)&1)<<j); ct+=(S[i]>0); } if(!ct) continue; for(int ss=0;ss<MAXN;ss++) F[1][ss]=val[1][S[1]^ss]+K[1][ss]; for(int i=2;i<=m;i++){ for(int sta=0;sta<MAXN;sta++){ LL res=INF; F[i][sta]=val[i][S[i]^sta]+K[i][sta]; for(int last=0;last<MAXN;last++) res=min(res,G[i-1][sta^last]+F[i-1][last]); F[i][sta]+=res; } } LL res=INF; for(int i=0;i<MAXN;i++) res=min(res,F[m][i]); ans+=(res<<k); } printf("%lld\n",ans); return 0; }