题目大意:
  一个$n\times m(n,m\leq400)$的网格图中,每个格子上放了两个三明治,摆放的方式分为'N'和'Z'两种。一个三明治可以被拿走当且仅当与该三明治的两条直角边相邻的三明治均被拿走或与该三明治斜边相邻的三明治被拿走。问对于每个格子,想要拿走这个格子中的所有三明治至少需要先拿走多少三明治。

思路:
  对于同一个格子,不难发现这一个格子中两个三明治接连被拿走一定是最优的。
  于是这题就和每个单独的三明治取走顺序没什么关系了,只和每个方格取走顺序及三明治的摆放方式有关。
  $O(n^2)$枚举每个格子$(x,y)$,假设它是因为$(x-1,y)$和$(x,y-1)$被取走后才被取走,我们可以$O(n^2)$DFS出最优情况下,取走每个格子之前一定要取走哪些格子。时间复杂度$O(n^4)$,bitset优化为$O(\frac{n^4}{\omega})$。
  不难发现,若$(x,y)$是因为$(x-1,y)$被取走才被取走的,$(x-1,y)$不可能因为$(x,y)$被取走才被取走。因此对于同一行的格子,我们可以让后面的DFS重复利用前面DFS出的信息。DFS是$O(n^2)$的,每一行要重新DFS,时间复杂度是$O(n^3)$。
  具体实现上,可以用$0\sim3$来表示不同的方向。若摆放方式为'N'的格子,一个直角边的方向为$d$,则另一个直角边的方向为$d\oplus3$;若摆放方式为'Z'的格子,一个直角边的方向为$d$,则另一个直角边的方向为$d\oplus1$。搜索时的一系列分类讨论可以通过简单的位运算实现。

 #include<cstdio>
#include<cctype>
#include<algorithm>
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'';
while(isdigit(ch=getchar())) x=(((x<<)+x)<<)+(ch^'');
return x;
}
inline bool getblock() {
register char ch;
while(!isalpha(ch=getchar()));
return ch=='N';
}
const int N=,inf=0x7fffffff;
const int dx[]={,-,,},dy[]={-,,,};
bool a[N][N];
int n,m,f[N][N],ans[N][N],tmp,flag;
inline bool check(const int &x,const int &y) {
return x>=&&x<n&&y>=&&y<m;
}
void dfs(const int &x,const int &y,const int &d) {
if(!~f[x][y]) {
flag=true;
return;
}
if(f[x][y]) return;
tmp+=;
f[x][y]=-;
const int p=a[x][y]?:;
if(check(x-dx[d],y-dy[d])) dfs(x-dx[d],y-dy[d],d);
if(check(x-dx[d^p],y-dy[d^p])) dfs(x-dx[d^p],y-dy[d^p],d^p);
f[x][y]=;
}
int main() {
for(register int T=getint();T;T--) {
n=getint(),m=getint();
for(register int i=;i<n;i++) {
for(register int j=;j<m;j++) {
a[i][j]=getblock();
}
}
for(register int i=;i<n;i++) {
flag=tmp=;
for(register int i=;i<n;i++) {
for(register int j=;j<m;j++) {
f[i][j]=;
}
}
for(register int j=;j<m;j++) {
if(!flag) dfs(i,j,);
ans[i][j]=flag?inf:tmp;
}
flag=tmp=;
for(register int i=;i<n;i++) {
for(register int j=;j<m;j++) {
f[i][j]=;
}
}
for(register int j=m-;~j;j--) {
if(!flag) dfs(i,j,);
ans[i][j]=std::min(ans[i][j],flag?inf:tmp);
}
}
for(register int i=;i<n;i++) {
for(register int j=;j<m;j++) {
printf("%d%c",ans[i][j]!=inf?ans[i][j]:-," \n"[j==m-]);
}
}
}
return ;
}

[JOISC2016]サンドイッチ的更多相关文章

随机推荐

  1. linux path环境变量基础

    系统环境变量与个人环境变量的配置文件 系统级别的配置文件:  /etc/profile :这个文件预设了几个重要的变量,例如PATH, USER, LOGNAME, MAIL, INPUTRC, HO ...

  2. springboot08 jdbc

    一.JDBC&连接池 1. jdbc介绍 ​ JDBC(Java DataBase Connectivity ,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数 ...

  3. php session访问限制

    登录 <?php // 启动会话 session_start(); // 注册登陆成功的 admin 变量,并赋值 true $_SESSION["admin"] = tru ...

  4. c++知识点总结--new的一些用法

    new operator 将对象产生与heap,不但分配内存而且为该对象调用一个constructor   operator new只是分配内存,没有constructor被调用 有个一个特殊版本,称 ...

  5. STL之set&multiset使用简介

    关于set,必须说明的是set关联式容器.set作为一个容器也是用来存储同一数据类型的数据类型,并且能从一个数据集合中取出数据,在set中每个元素的值都唯一,而且系统能根据元素的值自动进行排序.应该注 ...

  6. poj 3436 网络流构图经典

    ACM Computer Factory Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6012   Accepted: 2 ...

  7. Codeforces Round #387 (Div. 2) 747F(数位DP)

    题目大意 给出整数k和t,需要产生一个满足以下要求的第k个十六进制数 即十六进制数每一位上的数出现的次数不超过t 首先我们先这样考虑,如果给你了0~f每个数字可以使用的次数num[i],如何求长度为L ...

  8. HTML标签的使用要注意语义化

    语义化标签:你认为用什么标签最能描述这块内容,觉得这样表述更有意义,那么就可以使用这个标签. 现在的浏览器对CSS支持都挺完善的(不包括CSS3),讲究的是结构与表现相分离,结构与行为相分离,一个WE ...

  9. mac平台打造犀利的Android Studio开发环境

    0x0 背景介绍  随着Android Studio功能越来越强大,Android平台的开发者们基本上都从原来的Eclipse + ADT 转到了AS上.本文就记录自己在配置AS环境过程中遇到的各种问 ...

  10. shell脚本——项目2

    案例名称:发送告警邮件 背景: 外部邮箱的服务器(163等) 安装mailx(yum) 配置邮箱信息 vim /etc/mail.rc #配置自己的邮箱信息 set from=18906534060@ ...