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;
}
posted @ 2018-10-09 14:31  OYJason  阅读(240)  评论(0编辑  收藏  举报