(WC2018模拟十二)【FJOI2016集训Day7T3】Xor-Mul棋盘

是不是应该第100篇博文纪念一下?

题解:

本质简单题。。。但是我没仔细看这题。。。

观察它的两个式子,都是xor完再乘以某个数,意味着d数组的每个二进制位对答案的贡献都是独立的,可以每一位分开处理。

由于每一列只和相邻的列有连边,每一列的点只有和相邻列的点的关系会对答案有影响(语文不好,感性理解),因此从左到右递推的话只用存最后一列的结果就行了;

由于n很小,用状压DP记录当前扫描线上的数字状态,逐格暴力转移即可。

代码:

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<cmath>
 6 #include<queue>
 7 #define inf 1000000000000000
 8 #define eps 1e-9
 9 using namespace std;
10 typedef long long ll;
11 int N,n,m,a[6][10001],b[6][10001],e1[6][10001],e2[6][10001];
12 ll ans=0,tmp,f[2][51];
13 int chk(int a,int b){
14     return (!b)?0:(a>>(b-1))&1;
15 }
16 int main(){
17     scanf("%d%d",&n,&m);
18     N=1<<n;
19     for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%d",&a[i][j]);
20     for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%d",&b[i][j]);
21     for(int i=1;i<=n;i++)for(int j=2;j<=m;j++)scanf("%d",&e1[i][j]);
22     for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%d",&e2[i][j]);
23     for(int t=0;t<=19;t++){
24         memset(f[0],0,sizeof(f[0]));
25         for(int i=1;i<=m;i++){
26             for(int j=1;j<n;j++){
27                 for(int k=0;k<N;k++){
28                     f[1][k]=min(f[0][k],f[0][k^(1<<j-1)]+e1[j][i])+((chk(k,j)==chk(k,j-1))?0:e2[j-1][i])+((chk(k,j)==chk(a[j][i],t+1))?0:b[j][i]);
29                 }
30                 memcpy(f[0],f[1],sizeof(f[1]));
31             }
32             for(int k=0;k<N;k++){
33                 f[1][k]=min(f[0][k],f[0][k^(1<<n-1)]+e1[n][i])+((chk(k,n)==chk(k,n-1))?0:e2[n-1][i])+((chk(k,n)==chk(k,1))?0:e2[n][i])+((chk(k,n)==chk(a[n][i],t+1))?0:b[n][i]);
34             }
35             memcpy(f[0],f[1],sizeof(f[1]));
36         }
37         tmp=inf;
38         for(int j=0;j<N;j++){
39             tmp=min(tmp,f[0][j]);
40         }
41         ans+=tmp*(1<<t);
42     }
43     printf("%lld
",ans);
44     return 0;
45 }
原文地址:https://www.cnblogs.com/dcdcbigbig/p/9762768.html