题解:P7306 [COCI2018-2019#1] Strah

分享一个 O(nmlogm) 的方法。

分析

考虑每次在 x 轴上固定左端点,然后移动 x 轴上的右端点,并统计答案。

考虑如何统计一个 1×n 的区域的贡献。

显然长度为 i 的区间有 ni+1 个,所以贡献即为:

f(n)=i=1ni(ni+1)=i=1n(n+1)ii2=((n+1)i=1ni)(i=1ni2)=((n+1)n(n+1)2)n(n+1)(2n+1)6=n(n+1)22n(n+1)(2n+1)6=n(n+1)(n+2)6

所以 x 轴左端点为 l,右端点为 r,高度为 h 的矩形区域的贡献为 (rl+1)f(h)

mdeque 来记录 y=m 的不适宜种植的格子的位置,再用一个 set 记录当前被占用的格子的位置。

每次移动 r 都先将 x=r 的不适宜种植的格子加入 set 中,然后统计答案。

时间复杂度 O(nmlogm)

Code

#include<bits/stdc++.h>
using namespace std;
#define maxn 2003
deque<int> lx[maxn];
int64_t f(int64_t n) {return n*(n+1)*(n+2)/6;}
string str;
set<int> s;
vector<int> dts[maxn];
int main()
{
int n, m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>str;
for(int j=1;j<=m;j++)
if(str[j-1]=='#') lx[j].emplace_back(i);
}
int64_t ans=0;
for(int i=1;i<=m;i++) lx[i].emplace_back(n+1);
for(int l=1;l<=n;l++)
{
s.clear();
s.emplace(0);
s.emplace(m+1);
int64_t sum=f(m);
for(int i=l;i<=n;i++) dts[i].clear();
for(int i=1;i<=m;i++)
if(lx[i].front()==l-1) lx[i].pop_front();
for(int i=1;i<=m;i++)
dts[lx[i].front()].emplace_back(i);
for(int r=l;r<=n;r++)
{
for(auto p:dts[r])
{
auto nxt=s.lower_bound(p);
auto pre=prev(nxt);
sum-=f(*nxt-*pre-1);
sum+=f(*nxt-p-1);
sum+=f(p-*pre-1);
s.emplace(p);
}
ans+=sum*(r-l+1);
}
}
cout<<ans<<'\n';
}

本文作者:Jimmy-LEEE

本文链接:https://www.cnblogs.com/redacted-area/p/18514173

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Jimmy-LEEE  阅读(5)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起