专栏文章
题解:AT_abc420_f [ABC420F] kirinuki
AT_abc420_f题解参与者 4已保存评论 6
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 6 条
- 当前快照
- 1 份
- 快照标识符
- @mio4zr0p
- 此快照首次捕获于
- 2025/12/02 13:27 3 个月前
- 此快照最后确认于
- 2025/12/02 13:27 3 个月前
题意就是求面积小于等于 且全为
. 的矩形数量。面积小于等于 这个限制正常很不好处理。考虑分治。
假设现在处理到的矩形为 ,在矩形较长的那边取中点划分成两个矩形 (这里假设 方向是长边),递归求解。
类似一维分治,考虑统计跨过 这条线的答案。
先悬线法找出从这条线出发左右两边最远延伸距离 ,然后枚举两个端点 来限制矩形的高,这样就化为一维问题:左边有 个格子,右边有 个格子,求长度不超过 的跨过线的区间个数。这个随便推推就可以 求。
考虑分析时间复杂度:悬线的过程复杂度是矩形大小,枚举端点是在短边进行的,也不会超过矩形大小,两维坐标都会递归对数次。所以复杂度是 的,随便过。
代码特好写,输入可以用 string 规避动态数组。
CPP#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=5e5+7;
const int N=5e5;
const int mod=998244353;
const int inf=0x3f3f3f3f;
int n,m,k,l[maxn],r[maxn];
string s[maxn];
int calc(int L,int R,int K){ // O(1) 算贡献
int lm=min(L,K-1),rm=max(0ll,min(lm,K-R));
return R*rm+(lm-rm)*K-lm*(lm+1)/2+rm*(rm+1)/2;
}
int cdq(int xl,int xr,int yl,int yr){
if(xl==xr&&yl==yr) return s[xl][yl]=='.';
if(xr-xl>yr-yl){
int mid=(xl+xr)>>1;
for(int i=yl;i<=yr;i++){ l[i]=r[i]=0;
for(int j=mid;j>=xl&&s[j][i]=='.';j--) l[i]++;
for(int j=mid+1;j<=xr&&s[j][i]=='.';j++) r[i]++;
}
int res=0;
for(int i=yl;i<=yr;i++){
int lmx=inf,rmx=inf;
for(int j=i;j<=yr;j++){
lmx=min(lmx,l[j]); rmx=min(rmx,r[j]);
res+=calc(lmx,rmx,k/(j-i+1));
}
}
return res+cdq(xl,mid,yl,yr)+cdq(mid+1,xr,yl,yr);
}else{
int mid=(yl+yr)>>1;
for(int i=xl;i<=xr;i++){ l[i]=r[i]=0;
for(int j=mid;j>=yl&&s[i][j]=='.';j--) l[i]++;
for(int j=mid+1;j<=yr&&s[i][j]=='.';j++) r[i]++;
}
int res=0;
for(int i=xl;i<=xr;i++){
int lmx=inf,rmx=inf;
for(int j=i;j<=xr;j++){
lmx=min(lmx,l[j]); rmx=min(rmx,r[j]);
res+=calc(lmx,rmx,k/(j-i+1));
}
}
return res+cdq(xl,xr,yl,mid)+cdq(xl,xr,mid+1,yr);
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin>>n>>m>>k;
for(int i=1;i<=n;i++) cin>>s[i];
cout<<cdq(1,n,0,m-1);
return 0;
}
相关推荐
评论
共 6 条评论,欢迎与作者交流。
正在加载评论...