当前位置:网站首页>CF1534F2-Falling Sand (Hard Version)
CF1534F2-Falling Sand (Hard Version)
2022-08-10 23:38:00 【QuantAsk】
正题
题目链接:https://www.luogu.com.cn/problem/CF1534F2
题目大意
有一个 n ∗ m n*m n∗m个网格,有的网格上有沙子,一个沙子被刷新后会下落到底并且刷新沿途中四周四连通的沙子,你可以选择一些沙子手动刷新。
现在要求第 i i i列至少有 a i a_i ai个沙子下落,求至少手动刷新多少个沙子。
1 ≤ n × m ≤ 4 × 1 0 5 1\leq n\times m\leq 4\times 10^5 1≤n×m≤4×105
解题思路
显然列要求的 a i a_i ai就是要求最下面的那 a i a_i ai个沙子被刷新。
手动刷新的肯定都是每一列位置最高的沙子,然后刷新关系可以表示成一张有向图,而且是平面图,那么就说明一个沙子被刷新的条件是手动刷新了某个区间中位置最高的沙子。
我们考虑求出这些区间,先建边,这样最多 4 n m 4nm 4nm条边,然后对于每个沙子要求区间的左端点我们从左往右从最高的沙子开始跑,然后每次走到的点标记删除,右区间就变成从右往左跑。
得到这些区间后我们转换成若干个形如区间 [ l , r ] [l,r] [l,r]中必须要有一个 1 1 1的限制,然后考虑 d p dp dp,用单调队列优化一下即可。
时间复杂度: O ( n m ) O(nm) O(nm)
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define p(x,y) ((((x)-1)*n)+(y))
using namespace std;
const int N=8e5+10;
struct node{
int to,next;
}a[N*4];
int n,m,tot,ls[N],l[N],r[N],lim[N],f[N];
deque<int> q;vector<int> v[N];char s[N];
void addl(int x,int y){
a[++tot].to=y;
a[tot].next=ls[x];
ls[x]=tot;return;
}
void dfsl(int x){
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(l[y])continue;
l[y]=l[x];dfsl(y);
}
return;
}
void dfsr(int x){
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(r[y])continue;
r[y]=r[x];dfsr(y);
}
return;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%s",s+1);
for(int j=1;j<=m;j++)
if(s[j]=='#')
v[j].push_back(n-i+1);
}
for(int i=1;i<=m;i++){
if(v[i].empty())continue;
for(int j=0;j<v[i].size()-1;j++){
addl(p(i,v[i][j]),p(i,v[i][j+1]));
if(v[i][j+1]+1==v[i][j])addl(p(i,v[i][j+1]),p(i,v[i][j]));
}
for(int g=-1;g<2;g++){
if(!g||!v[i+g].size())continue;
int z=0,_=0;
while(z<v[i+g].size()&&v[i+g][z]>v[i][0])z++;
for(int h=v[i][0];h>=1;h--){
if(_<v[i].size()-1&&h==v[i][_+1])_++;
if(z<v[i+g].size()&&h==v[i+g][z])
addl(p(i,v[i][_]),p(i+g,v[i+g][z])),z++;
}
}
}
for(int i=1;i<=m;i++){
if(v[i].empty())continue;
int x=p(i,v[i][0]);
if(!l[x])l[x]=i,dfsl(x);
}
for(int i=m;i>=1;i--){
if(v[i].empty())continue;
int x=p(i,v[i][0]);
if(!r[x])r[x]=i,dfsr(x);
}
for(int i=1,x;i<=m;i++){
scanf("%d",&x);
for(int j=v[i].size()-1;j>=(int)v[i].size()-x;j--)
{
int y=p(i,v[i][j]);lim[r[y]]=max(lim[r[y]],l[y]);}
}
q.push_back(0);
for(int i=1;i<=m;i++){
f[i]=max(f[i],f[q.front()]+1);
while(!q.empty()&&f[q.back()]>=f[i])q.pop_back();
q.push_back(i);
while(!q.empty()&&q.front()<lim[i])q.pop_front();
}
printf("%d\n",f[q.front()]);
return 0;
}
边栏推荐
- VR全景+安全科普教育,让学生们提高安全意识
- call,apply,bind指定函数的this指向详解,功能细节,严格和非严格模式下设定this指向
- 好用的翻译插件-一键自动翻译插件软件
- 《剑指offer》题解——week2(持续更新)
- 【C语言篇】操作符之 位运算符详解(“ << ”,“ >> ”,“ & ”,“ | ”,“ ^ ”,“ ~ ”)
- sklearn.datasets.make_circles
- MySQL数据库基础操作
- ROS实验笔记之——安装QPEP以及Intel-MKL
- CSDN21天学习挑战赛之折半查找
- Timers, synchronous and asynchronous APIs, file system modules, file streams
猜你喜欢
随机推荐
[C] the C language program design, dynamic address book (order)
回收站的文件删了怎么恢复,回收站文件恢复的两种方法
7. yaml
oai 采样频率计算
推进牛仔服装的高质量发展
特殊类与类型转换
HFCTF 2021 Internal System writeup
线程相关知识点
Google Chrome73~81版本浏览器的跨域问题解决方案
App regression testing, what are the efficient testing methods?
花环灯问题
22年全国程序员1月薪资出炉,才知道年薪 40 万以上的有这么多?
Promise in detail
CW614N铜棒CuZn39Pb3对应牌号
[C language articles] Expression evaluation (implicit type conversion, arithmetic conversion)
VR全景+安全科普教育,让学生们提高安全意识
SQL注入基础---order by \ limit \ 宽字节注入
ACTF 2022 writeup
How to recover data from accidentally deleted U disk, how to recover deleted data from U disk
点云中的一些名词解释
![Which translation software is more accurate [Free]](/img/12/33d6724cfe8e8fe12a131c1e5e7a69.png)







