Problem 2250 不可能弹幕结界

Time Limit: 1000 mSec    Memory Limit : 65536 KB

Problem Description

咲夜需要穿过一片弹幕区,由于咲夜发动了符卡“The World”,所以弹幕是静止的。这片弹幕区以一个n*m的矩阵的形式给出。

‘.’表示这个位置是安全的,’x’表示这个位置上是有子弹的,禁止通行。咲夜每次能向左、右、下三个方向的相邻格子走,但是不能向上走。 同时由于时间有限,咲夜在进入每一行之后最多只能横向走k步。你可以简单地认为我们的目标就是从第0行走到第n+1行,起点和终点可以是在第0行和第n+1行的任意位置,当然第0行和第n+1行都是没有弹幕的。

然而这是号称不可能的弹幕结界,所以咲夜很可能无法穿过这片弹幕,所以咲夜准备了一个只能使用一次的技能,纵向穿越,她可以从任意位置直接穿越到另外任意一行的同一个位置(所在列不变),当然她只能向下穿越,不能向上穿越。穿越的距离越远,耗费的资源自然越多,所以她想知道最短的穿越距离,才能使她成功通过这片弹幕区。

Input

输入包含多组数据。

对于每组数据:

第一行输入三个整数n,m,k,如上所述。

接下下输入一个n×m的矩阵,’.’表示当前这格没有子弹,是安全的,’x’表示这各有子弹,禁止通行。

N<=1000,k<=m<=1000

Output

对于每组数据输出一个整数,表示最短的穿越距离。

Sample Input

6 5 2 x.x.. ..xx. .xxx. xx.xx xx..x ..x.x 4 4 1 .xxx .xxx ...x xx.x

Sample Output

3 2

Hint

对于第一组样例,最优解是从第一行第二列走到第三行第一列,然后跳到第6行第一列,穿越距离为(6 – 3) = 3。

分析:考虑从上往下走;

   状态转移为如果当前点能够到达,那么下一行这一列如果是‘.’的话,那么这个点左右可到达的范围也能到达;

   即if(ok(i,j))ok(i+1,l[i+1][j]~r[i+1][j]);这个标记差分即可;

   所以预处理每个点左右能到达的范围;

   从下往上也一样,最后找一下行间隔最小即可,注意边界;

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <climits>
#include <cstring>
#include <string>
#include <set>
#include <bitset>
#include <map>
#include <queue>
#include <stack>
#include <vector>
#include <cassert>
#define rep(i,m,n) for(i=m;i<=n;i++)
#define mod 1000000007
#define inf 0x3f3f3f3f
#define vi vector<int>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define ll long long
#define pi acos(-1.0)
#define pii pair<int,int>
#define sys system("pause")
const int maxn=1e3+;
const int N=2e5+;
using namespace std;
ll gcd(ll p,ll q){return q==?p:gcd(q,p%q);}
ll qpow(ll p,ll q){ll f=;while(q){if(q&)f=f*p%mod;p=p*p%mod;q>>=;}return f;}
int n,m,k,t,l[maxn][maxn],r[maxn][maxn],dp[maxn],up[maxn][maxn],dw[maxn][maxn];
char a[maxn][maxn];
int main()
{
int i,j;
while(~scanf("%d%d%d",&n,&m,&k))
{
rep(i,,n)scanf("%s",a[i]+);
memset(dp,-,sizeof(dp));
memset(up,,sizeof(up));
memset(dw,,sizeof(dw));
rep(i,,n)
{
rep(j,,m)
{
if(j==)l[i][j]=j;
else l[i][j]=a[i][j-]!='x'?l[i][j-]:j;
if(l[i][j]<j-k)l[i][j]=j-k;
}
for(j=m;j>=;j--)
{
if(j==m)r[i][j]=j;
else r[i][j]=a[i][j+]!='x'?r[i][j+]:j;
if(r[i][j]>j+k)r[i][j]=j+k;
}
}
rep(i,,m)if(a[][i]=='.')up[][i]=;
rep(i,,n)
{
if(i!=)
{
rep(j,,m)up[i][j]+=up[i][j-];
}
rep(j,,m)
{
if(up[i][j]&&a[i+][j]=='.')up[i+][l[i+][j]]++,up[i+][r[i+][j]+]--;
}
}
rep(i,,m)if(a[n][i]=='.')dw[n][i]=;
for(i=n;i>=;i--)
{
if(i!=n)
{
rep(j,,m)dw[i][j]+=dw[i][j-];
}
rep(j,,m)
{
if(dw[i][j]&&a[i-][j]=='.')dw[i-][l[i-][j]]++,dw[i-][r[i-][j]+]--;
}
}
int ret=n+;
for(i=n;i>=;i--)
{
rep(j,,m)
{
if(up[i][j])ret=min(ret,n+-i);
if(up[i][j]&&dp[j]!=-)ret=min(ret,dp[j]-i);
if(dw[i][j])dp[j]=i,ret=min(ret,i);
}
}
rep(i,,m)if(up[n][i])ret=;
printf("%d\n",ret);
}
return ;
}

最新文章

  1. FTP工具类开发
  2. VS使用技巧——统计代码行数
  3. 老贼博客php教程从零学习PHP开始写作,顺祝新同事快乐!
  4. AngularJS的学习--$on、$emit和$broadcast的使用
  5. [Android Pro] CPU占用计算方法
  6. Samba配置
  7. BZOJ1962 模型王子
  8. angular-xeditable
  9. Squid代理之反向代理
  10. jQuery基础学习4——jQuery容错性
  11. wcf的连接数
  12. Thrift 应用场景(收集版)
  13. forward 和redirect的区别
  14. linux memory release commands内存清理/释放命令
  15. python手动设置递归调用深度
  16. Django分页器的设置
  17. Consul之:服务注册与发现
  18. zookeeper 集群部署
  19. python 多环境共存 基础
  20. Mysql innodb_fast_shutdown

热门文章

  1. luogu 3808 【模板】AC自动机(简单版)
  2. Makefile 实际用例分析(三) ------- 是用GUN automake 处理自己的工程
  3. Flume Avor Source
  4. fprintf与stderr、stdout的使用
  5. 对腾讯云服务器linux系统进行分区格式化操作
  6. 枚举类enum的values()方法
  7. Windows(7/8/10)搭建Elasticsearch 6.x版本
  8. JavaScript--改变 HTML 样式
  9. 在vSphere Client上安装虚拟机工具VMware Tools
  10. mysql数据的操作