【九省联考2018】一双木棋

题面

https://www.luogu.org/problem/P4363

题解

很套路的$hash$状态$+dp$。

可知棋子形成的形状一定是一个连续的倒楼梯形(楼梯向右延伸的长度可以不连续,但一定单调)

$hash$轮廓就行了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define ri register int
#define N 11
#define LL long long
#define INF 1000000007
#define mod 1233107
using namespace std;
int a[N][N],b[N][N];
LL pow[N];
int n,m;
vector<int>f[mod];
vector<LL>g[mod];

int dfs(LL x) {
  int ln[N];
  int yx=x%mod;
  for (ri i=0;i<g[yx].size();i++) if (g[yx][i]==x) return f[yx][i];
  g[yx].push_back(x);
  f[yx].push_back(0);
  int tl=f[yx].size()-1;
  int tot=0,opt,ret;
  LL tx=x,nx;
  for (ri i=n;i>=1;i--) {
    ln[i]=x/pow[i];
    x%=pow[i];
  }
  ln[0]=m+1;
  for (ri i=1;i<=n;i++) tot+=ln[i];
  if (tot==n*m) return 0;
  if (tot%2==0) opt=1; else opt=0;
    
  if (opt) ret=-INF; else ret=INF;
  for (ri i=1;i<=n;i++) if (ln[i-1]>ln[i] && ln[i]+1<=m) {
    nx=tx+pow[i];
    if (opt) {
      int t=dfs(nx);
      if (a[i][ln[i]+1]+t>ret) ret=a[i][ln[i]+1]+t;
    }
    else {
      int t=dfs(nx);
      if (-b[i][ln[i]+1]+t<ret) ret=-b[i][ln[i]+1]+t;
    }
  }
  return f[yx][tl]=ret;
}

int main(){
  cin>>n>>m;
  for (ri i=1;i<=n;i++) 
    for (ri j=1;j<=m;j++) cin>>a[i][j];
  for (ri i=1;i<=n;i++)
    for (ri j=1;j<=m;j++) cin>>b[i][j];
  pow[1]=1LL;
  for (ri i=2;i<=n;i++) pow[i]=pow[i-1]*11LL;
  printf("%d
",dfs(0));
}
原文地址:https://www.cnblogs.com/shxnb666/p/11426246.html