[JOISC2016]サンドイッチ
题目大意:
一个$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]サンドイッチ的更多相关文章
随机推荐
- Kd-Tree&Ransac笔记
关于sift资源总结: http://blog.csdn.net/masibuaa/article/details/9191309 两个比较好的资源: https://my.oschina.net/k ...
- 【现代程序设计】homework-02
迟交了这么久,一定是0分了.可是我再怎么挣扎,还是不会.交了一维和二维的,这里说说思路吧.. 对于二维的情况,主要的思路就是将二维数组求矩形最大子数组的情况转化为一维的情况.因为所求的是矩形,我们就可 ...
- bpf 指令集
58 struct bpf_insn { 59 __u8 code; /* opcode */ 60 __u8 dst_reg:4; /* dest register */ 61 __u8 src_r ...
- hdu 2579 Dating with girls(2) (bfs)
Dating with girls(2) Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Oth ...
- 2016-2017 ACM-ICPC, Egyptian Collegiate Programming Contest (ECPC 16)
A.The game of Osho(sg函数+二项展开) 题意: 一共有G个子游戏,一个子游戏有Bi, Ni两个数字.两名玩家开始玩游戏,每名玩家从N中减去B的任意幂次的数,直到不能操作判定为输.问 ...
- 雅礼集训 Day1 T1 养花
养花 题目描述 小\(C\)在家种了\(n\)盆花,每盆花有一个艳丽度\(a_i\). 在接下来的\(m\)天中,每天早晨他会从一段编号连续的花中选择一盆摆放在客厅, 并在晚上放回. 同时每天有特定的 ...
- SQL UNPIVOT和PIVOT
/* table_source PIVOT( 聚合函数(value_column) FOR pivot_column IN(<column_list>) ) 完整语法: table_sou ...
- altera ip 核小究
用quartus的MegaWizard工具生成一个乘法器multiplier,会在工程目录下产生 multiplier.qip (可选) multiplier_bb.v (可选) multip ...
- mysql截取字符串与reverse函数
mysql的函数大全: http://www.jb51.net/Special/606.htm 这个网页上很多知识点,可以学习下,关于mysql的函数,也可以作为API查询: 这里只说下mysql的截 ...
- hdu 1847 Good Luck in CET-4 Everybody! SG函数SG引理
大学英语四级考试就要来临了,你是不是在紧张的复习?也许紧张得连短学期的ACM都没工夫练习了,反正我知道的Kiki和Cici都是如此.当然,作为在考场浸润了十几载的当代大学生,Kiki和Cici更懂得考 ...