CF1534F2 Falling Sand (Hard Version) 题解
题目链接
题目解法
- 做法1
一个沙子消失,会带走所有它所在列下面的沙子
我们记每列从下往上第 个沙子为关键点,第 列至少消失 个沙子等价于所有关键点都消失
一个显然的事情是:记一列最上面的沙子为起始点,则我们只会干扰起始点
第一感觉是找到一个沙子可以干扰的所有起始点,但它并不是一个列上的区间
但把这个东西反过来,一个沙子能被干扰到的起始点是一个区间
证明:假设存在 (左边部分类似),第 列的关键点不能被第 列的起始点干扰。如果第 列的起始点干扰第 列关键点的路径从第 列起始点的上方经过,那么第 列的起始点的起始点上方就有沙子,矛盾;如果路径从下方经过,那么第 列的起始点能干扰第 列的关键点,矛盾。
不难用 求出所有关键点能被干扰到的起始点的区间,现在问题变成有很多区间,我们要选最少的点,使得每个区间中都存在选择的点
这显然可以按右端点排序之后贪心求出
时间复杂度 - 做法2
沿用 F1 的思路,我们只把关键点缩点,且只需要关注度数为 的点
根据做法 1 的结论,非关键点能干扰的度数为 的点是一个区间,然后类似做法 1 一样做就好了
其实两个做法本质是相同的
做法 1 的代码:
#include <bits/stdc++.h> #define F(i,x,y) for(int i=(x);i<=(y);i++) #define DF(i,x,y) for(int i=(x);i>=(y);i--) #define ms(x,y) memset(x,y,sizeof(x)) #define SZ(x) (int)x.size()-1 #define all(x) x.begin(),x.end() #define pb push_back using namespace std; typedef long long LL; typedef unsigned long long ull; typedef pair<int,int> pii; template<typename T> void chkmax(T &x,T y){ x=max(x,y);} template<typename T> void chkmin(T &x,T y){ x=min(x,y);} template<typename T> void read(T &FF){ FF=0;int RR=1;char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1; for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48; FF*=RR; } const int N=400010; int n,m,a[N],L[N],R[N]; bool mp[N]; char str[N]; int ind(int x,int y){ return (x-1)*m+y;} void dfs1(int x,int y,int col){ if(L[ind(x,y)]) return; L[ind(x,y)]=col; if(x<n) dfs1(x+1,y,col); if(x>1&&mp[ind(x-1,y)]) dfs1(x-1,y,col); if(y>1&&mp[ind(x,y-1)]) dfs1(x,y-1,col); if(y<m&&mp[ind(x,y+1)]) dfs1(x,y+1,col); } void dfs2(int x,int y,int col){ if(R[ind(x,y)]) return; R[ind(x,y)]=col; if(x<n) dfs2(x+1,y,col); if(x>1&&mp[ind(x-1,y)]) dfs2(x-1,y,col); if(y>1&&mp[ind(x,y-1)]) dfs2(x,y-1,col); if(y<m&&mp[ind(x,y+1)]) dfs2(x,y+1,col); } pii rng[N]; int main(){ read(n),read(m); F(i,1,n){ scanf("%s",str+1); F(j,1,m) if(str[j]=='#') mp[ind(i,j)]=1; } F(i,1,m) read(a[i]); F(j,1,m) F(i,1,n) if(mp[ind(i,j)]) dfs1(i,j,j); DF(j,m,1) F(i,1,n) if(mp[ind(i,j)]) dfs2(i,j,j); int cnt=0; F(j,1,m) if(a[j]) DF(i,n,1) if(mp[ind(i,j)]) if(!(--a[j])){ rng[++cnt]={R[ind(i,j)],L[ind(i,j)]}; break; } sort(rng+1,rng+cnt+1); int cur=0,ans=0; F(i,1,cnt) if(rng[i].second>cur) ans++,cur=rng[i].first; printf("%d\n",ans); return 0; }
标签:
Codeforces
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通