AtCoder AGC028-F:Reachable Cells
越来越喜欢AtCoder了,遍地都是神仙题。
题意:
给定一个\(N\)行\(N\)列的迷宫,每一个格子要么是障碍,要么是空地。每一块空地写着一个数码。在迷宫中,每一步只允许向右、向下走,且只能经过空地。
对于每两个连通(从一个可到达另一个)的格子,求出它们数码的乘积。问所有这种乘积的和。
\(1 \leq N \leq 500\)
思路:
容易把到达关系建成一张DAG,我们要做的就只是:对每一个点,求他所有后继的权值和。但是DAG后继数问题,众所周知只有\(O(|E||V|)\)做法,于是换思路。
我们猜测,从一个格子出发,可以达到的点集(即后继集合)大约是一个凸包的形状。
而这个猜想也大约是对的,然而要使其完全正确,还有很长的路要走。
以下用\((i,j)\)表示第\(i\)行第\(j\)列的格子。编号从1开始。
第一步
4177143673
7#########
5#1716155#
6#4#####5#
2#3#597#6#
6#9#8#3#5#
5#2#899#9#
1#6#####6#
6#5359657#
5#########
以上是样例4的网格,由嵌套的3段环状障碍组成。不妨由内而外称为一环,二环,三环。
注意到对于\((3,3)\),他的所有后继在矩形\((3,3) - (9,9)\)里,被三环包围。然而,二环以内的部分却不是\((3,3)\)的后继,需要想办法剔除。
首先发现,如果\((i-1,j)\)和\((i,j-1)\)都是障碍,那么空地\((i,j)\)不会是其他任何格子的后继。因此,如果已经求完了\((i,j)\)自己的后继,完全可以把\((i,j)\)改成障碍。改完之后,可能会产生新的满足同样性质的空地,于是递归地改下去即可。
我们可以考虑从下到上,对每一行分别求答案。每当求完一行所有格子的答案,就把这一行里能改成障碍的都(递归地)修改掉,再进入上一行。
经过这样的操作,就可以证明:
假如第\(i+1\)行到第\(n\)行,都已执行过修改,那么对于空地\((i,j)\),存在一个简单多边形,恰好包含\((i,j)\)的所有后继和若干障碍。
再进一步,这个多边形由一段“上边界”和一段“下边界”拼成,而每一段边界都是仅向下、向右延伸的阶梯型折线。
第二步
我们试着对\((i,j)\),求出他的后继多边形的两段边界。以下给出了求下边界的大致的伪代码。
starting position := (i,j)
while not touching boundary:
while adjacent empty cell exists:
if moving down reaches empty cell:
move down
else:
move right
while (i,j) cannot reach current position:
move right
上边界类似。
如果可以\(O(1)\)地判断,\((i,j)\)是否能够到达\(current position\),那么这段代码的复杂度就是\(O(N)\),总复杂度就是\(O(N^3)\),可过。
第三步
先考虑求下边界时对连通性的判断。
引入“添加”操作,他做的事情是,把某个格子的后继中,所有被修改成障碍的空地还原。此操作的复杂度正比于被还原的格子数量,具体实现见代码中的\(add\)函数。
先清空第\(i\)行及以下的行(都改成障碍),再对第\(i\)行的前\(j\)个格子做添加操作,易证所得的网格满足:
1、\((i,j)\)的所有后继都依然是空地。
2、第\(i\)行下方的所有空地都由第\(i\)行的前\(j\)个格子可达。
3、第一步中的结论依然成立。
注意到先前那段伪代码的流程是:
(1)、沿着\((i,j)\)尽可能向下走,直到无路可走为止。
(2)、从路径尾端不断向右移,直到遇见从\((i,j)\)可达的空地。
(3)、以当前位置为起点,重复(1)。
考虑(2)中遇到的任意一个空地\(P\),则有以下结论(画图后不难理解):
若有\(k \leq j\),\(P\)在以\((i,k)\)为起点的路径上,则此路径必然与一起点为\((i,j)\)的路径相交。
既然有交点,容易发现\(P\)一定由\((i,j)\)可达。于是,若使用以上算法,则(2)中遇到的所有空地都与\((i,j)\)连通。
求下边界解决了,求上边界的话,用对称大法也能同理解决。
细节不少,详见代码。
代码:
#include <bits/stdc++.h>
#pragma GCC optimize(3)
using namespace std;
#define iinf 2000000000
#define linf 1000000000000000000LL
#define ulinf 10000000000000000000ull
#define MOD1 1000000007LL
#define mpr make_pair
typedef long long LL;
typedef unsigned long long ULL;
typedef unsigned long UL;
typedef unsigned short US;
typedef pair < int , int > pii;
clock_t __stt;
inline void TStart(){__stt=clock();}
inline void TReport(){printf("\nTaken Time : %.3lf sec\n",(double)(clock()-__stt)/CLOCKS_PER_SEC);}
template < typename T > T MIN(T a,T b){return a<b?a:b;}
template < typename T > T MAX(T a,T b){return a>b?a:b;}
template < typename T > T ABS(T a){return a>0?a:(-a);}
template < typename T > void UMIN(T &a,T b){if(b<a) a=b;}
template < typename T > void UMAX(T &a,T b){if(b>a) a=b;}
int n,g[505][505],s[505][505],mx[505];
bool e[505][505];
LL res;
int readchar(){
char c=getchar();
while(c==' ' || c=='\n') c=getchar();
if(c=='#') return 0;
return c-'0';
}
void add(int x,int y){
e[x][y]=1;
if(x<n-1 && g[x+1][y] && !e[x+1][y]) add(x+1,y);
if(y<n-1 && g[x][y+1] && !e[x][y+1]) add(x,y+1);
}
int getlower(int x,int y){
int cx=x,cy=y,ret=(y?s[x][y-1]:0);
mx[y]=x;
while(1){
while(1){
if(cx+1<n && e[cx+1][cy]){
++cx;
mx[y]=cx;
ret+=(cy?s[cx][cy-1]:0);
}
else if(cy+1<n && e[cx][cy+1]){
++cy;
}
else break;
}
bool found=0;
while(cy+1<n){
++cy;
if(e[cx][cy]){
found=1;
break;
}
}
if(!found) break;
}
return ret;
}
int getupper(int x,int y){
int cx=x,cy=y,ret=0;
while(1){
while(1){
if(cy+1<n && e[cx][cy+1]){
++cy;
}
else if(cx+1<n && e[cx+1][cy]){
ret+=s[cx][cy];
++cx;
}
else break;
}
bool found=0;
while(cx<n-1){
ret+=s[cx][cy];
++cx;
if(cx>mx[y]) break;
if(e[cx][cy]){
found=1;
break;
}
}
if(!found || cx>mx[y]) break;
}
if(cx<=mx[y]) ret+=s[cx][cy];
return ret;
}
void solveline(int x){
int i,j,k;
memcpy(s,g,sizeof(g));
for(i=0;i<n;++i){
for(j=1;j<n;++j){
s[i][j]+=s[i][j-1];
}
}
for(i=x;i<n;++i) memset(e[i],0,sizeof(e[i]));
for(i=0;i<n;++i){
if(!g[x][i]) continue;
add(x,i);
res-=(LL)g[x][i]*(LL)getlower(x,i);
}
for(i=x;i<n;++i) memset(e[i],0,sizeof(e[i]));
for(i=n-1;i>=0;--i){
if(!g[x][i]) continue;
add(x,i);
res+=(LL)g[x][i]*(LL)(getupper(x,i)-g[x][i]);
}
}
void del(int x,int y){
if((!x || !g[x-1][y]) && (!y || !g[x][y-1])){
g[x][y]=0;
if(x<n-1 && g[x+1][y]) del(x+1,y);
if(y<n-1 && g[x][y+1]) del(x,y+1);
}
}
int main(){
// inputting start
// 数据结构记得初始化! n,m别写反!
int i,j,k;
scanf("%d",&n);
for(i=0;i<n;++i){
for(j=0;j<n;++j){
g[i][j]=readchar();
}
}
#ifdef LOCAL
TStart();
#endif
// calculation start
// 数据结构记得初始化! n,m别写反!
for(i=0;i<n;++i){
for(j=0;j<n;++j){
e[i][j]=(!!g[i][j]);
}
}
for(i=n-1;i>=0;--i){
solveline(i);
for(j=0;j<n;++j){
if(g[i][j]) del(i,j);
}
}
printf("%lld\n",res);
#ifdef LOCAL
TReport();
#endif
return 0;
}
AtCoder AGC028-F:Reachable Cells的更多相关文章
- Atcoder abc187 F Close Group(动态规划)
Atcoder abc187 F Close Group 题目 给出一张n个点,m条边的无向图,问删除任意数量的边后,留下来的最少数量的团的个数(\(n \le 18\) ) 题解 核心:枚举状态+动 ...
- AtCoder Grand Contest 002 F:Leftmost Ball
题目传送门:https://agc002.contest.atcoder.jp/tasks/agc002_f 题目翻译 你有\(n*k\)个球,这些球一共有\(n\)种颜色,每种颜色有\(k\)个,然 ...
- 2018年全国多校算法寒假训练营练习比赛(第四场)F:Call to your teacher
传送门:https://www.nowcoder.net/acm/contest/76/F 题目描述 从实验室出来后,你忽然发现你居然把自己的电脑落在了实验室里,但是实验室的老师已经把大门锁上了.更糟 ...
- 牛客练习赛13D:幸运数字Ⅳ(康托展开) F:关键字排序
链接:https://www.nowcoder.com/acm/contest/70/D 题目: 定义一个数字为幸运数字当且仅当它的所有数位都是4或者7. 比如说,47.744.4都是幸运数字而5.1 ...
- 并不对劲的CF1245E&F:Cleaning Ladders
CF1245 E. Hyakugoku and Ladders 题目大意 有一个10 \(\times\) 10的网格,你要按这样的路径行走: 网格中有一些单向传送门,每个传送门连接的两个格子在同一列 ...
- [AtCoder ARC076] F Exhausted?
霍尔定理 + 线段树? 咱学学霍尔定理... 霍尔定理和二分图完美匹配有关,具体而言,就是定义了二分图存在完美匹配的充要条件: 不妨设当前二分图左端集合为 X ,右端集合为 Y ,X 与 Y 之间的边 ...
- Contest2037 - CSU Monthly 2013 Oct (problem F :ZZY and his little friends)
http://acm.csu.edu.cn/OnlineJudge/problem.php?cid=2037&pid=5 [题解]: 没想通这题暴力可以过.... [code]: #inclu ...
- codeforces 277.5 div2 F:组合计数类dp
题目大意: 求一个 n*n的 (0,1)矩阵,每行每列都只有两个1 的方案数 且该矩阵的前m行已知 分析: 这个题跟牡丹江区域赛的D题有些类似,都是有关矩阵的行列的覆盖问题 牡丹江D是求概率,这个题是 ...
- 【ATcoder s8pc_3 F】 寿司
http://s8pc-3.contest.atcoder.jp/tasks/s8pc_3_f (题目链接) 题意 有一个长度为$N$的数列$A$,初始为$0$.$Q$次操作,每次两个参数$x,y$. ...
随机推荐
- vue-cli3 项目从搭建优化到docker部署
项目地址 vue-cli3-project 欢迎 star 原文地址 https://www.ccode.live/lentoo/list/9?from=art 1. 创建一个vue项目 相信大部分人 ...
- spring-4.3.16+xfire-spring-1.2.6版本升级
最近爆了个spring的漏洞,然后公司整体要求升级spring到最新版本,然后搞四了一大批猿人. spring-4.*的最新版本是4.3.16(稳定版) xfire-spring-1.2.6(最新版- ...
- leetcode 198、打家劫舍
You are a professional robber planning to rob houses along a street. Each house has a certain amount ...
- OO思想举例,控制翻转,依赖注入
(转自kumaws,原帖地址:http://www.cnblogs.com/kumaws/archive/2009/04/06/from_interface_to_DependencyInjectio ...
- Android(java)学习笔记17:网络编程的概述
1. 计算机网络 计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统 ...
- SpringMVC学习记录三——8 springmvc和mybatis整合
8 springmvc和mybatis整合 8.1 需求 使用springmvc和mybatis完成商品列表查询. 8.2 整合思路 springmvc+mybaits的 ...
- Android学习笔记_57_ExpandableListView控件应用
1.布局文件: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:andr ...
- POJ 2533 Longest Ordered Subsequence(裸LIS)
传送门: http://poj.org/problem?id=2533 Longest Ordered Subsequence Time Limit: 2000MS Memory Limit: 6 ...
- 【转载】Atom 是一款各方面体验都很像 Sublime Text 的编辑器
转载:http://www.appinn.com/atom-editor/ Atom 是一款各方面体验都很像 Sublime Text 的编辑器,它由 Github 出品,目前免费. Atom 功能的 ...
- js读取跨域webapi传送回来的cookie 要点
1.webapi 返回cookie时,httpOnly=false 2.webapi 接收Origins 不能为* 3.js端 请求时,withCredentials必须: true //`wit ...