BZOJ4676: Xor-Mul棋盘

来源:互联网 发布:电钢琴选购知乎 编辑:程序博客网 时间:2024/06/03 18:16

题目大意:给定一个网格棋盘,每条边有一个权值c,每个点有两个权值a,b,你需要给每个点一个权值d,使得每个点的(a^d)*c的和+每条边的两个端点的d异或起来*c的和最小


首先因为是位运算,所以每一位相互独立,可以分开算

然后就能想到状压DP,因为n只有5而且每一列只和上一列有关系,所以可以设f[i][j]表示第i列的状态为j,目前产生的代价最小值

这样转移的时候枚举上一列的情况,然后计算新产生的权值,时间复杂度是O(位运算的每一位*m*状态数*上一列的状态数*计算对应的权值)=O(20*M*2^n*2^n*n)=O(20NM*4^n)

显然是过不了的

我们考虑优化,我们可以发现计算新的权值这一步挪到外面去做,因为他跟你是哪一位没关系,只需要O(M*4^n)预处理出对于每一列来说这列状态和上一列状态分别是j和k时边产生的代价,再O(NM*2^n)当这一列状态为j时,点产生的代价,这样在枚举每一位时就不需要O(N)计算新产生的权值了!

总时间复杂度降成了O(20M*4^N)


#pragma GCC optimize("O2")#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#define N 10010using namespace std;long long n,m;long long a[6][N],b[6][N],c1[6][N],c2[6][N];long long A[6][N];long long f[N][32],F[N][32][32];bool p(long long x,long long k){    return ((x&(1<<(k-1)))!=0);}long long solve(long long x){    long long i,j,k,l;    for(i=1;i<=n;i++)    for(j=1;j<=m;j++)    {        if(a[i][j]&x) A[i][j]=1;        else A[i][j]=0;    }    for(i=1;i<=m;i++)    for(k=0;k<(1<<n);k++)    {        long long tmp=0;        for(j=1;j<=n;j++)        {            tmp+=b[j][i]*(A[j][i]^p(k,j));            if(j==n)            tmp+=c2[j][i]*(p(k,n)^p(k,1));            else            tmp+=c2[j][i]*(p(k,j)^p(k,j+1));        }        f[i][k]=1e18;        //if(k==3) cout<<tmp;        for(l=0;l<(1<<n);l++)        {            long long tmp2=0;            f[i][k]=min(f[i][k],f[i-1][l]+F[i][k][l]);        }        f[i][k]+=tmp;        /*  if(k==3)        cout<<i<<' '<<k<<' '<<f[i][k]<<endl;*/    }    long long minn=1e18;    for(i=0;i<(1<<n);i++)    minn=min(minn,f[m][i]);    return minn*x;}int main(){    scanf("%lld%lld",&n,&m);    long long i,j,k,l;    for(i=1;i<=n;i++)    for(j=1;j<=m;j++)    scanf("%lld",&a[i][j]);    for(i=1;i<=n;i++)    for(j=1;j<=m;j++)    scanf("%lld",&b[i][j]);    for(i=1;i<=n;i++)    for(j=1;j<m;j++)    scanf("%lld",&c1[i][j]);    for(i=1;i<=n;i++)    for(j=1;j<=m;j++)    scanf("%lld",&c2[i][j]);    for(i=1;i<=m;i++)    for(k=0;k<(1<<n);k++)    {        long long tmp=0;        for(l=0;l<(1<<n);l++)        {            long long tmp2=0;            for(j=1;j<=n;j++)            tmp2+=c1[j][i-1]*(p(k,j)^p(l,j));            F[i][k][l]=tmp2;        }    }    long long ans=0;    for(i=0;i<=19;i++)    ans+=solve(1<<i);    printf("%lld",ans);}

0 0
原创粉丝点击