没进 noip 的场外菜鸡选手。
Solution
可以发现 C
和 F
的相似之处在于左侧都有一条竖线,可以枚举这一条竖线,设它的上顶点向右可以拓展 \(a\) 个格子,下顶点向右可以拓展 \(b\) 个,下顶点向下可以拓展 \(c\) 个。
那么显然,该竖线对于 C
的贡献就是 \(a\times b\),对于 F
的贡献就是 \(a\times b\times c\)。可以做到预处理 \(O(n^2)\),枚举竖线 \(O(n^3)\)。
考虑优化,计算一个上顶点对于答案的贡献,如图:
红色节点最多拓展到绿色节点,那么在我们枚举竖线的过程中,对 C
的贡献为 \(\sum a\times b_i\) 即 \(a\sum b_i\),其中 \(i\) 为向下能够拓展到的节点。预处理 \(b_i\) 前缀和。
同理,设一个点能向下拓展 \(c\) 格,枚举上顶点,对 F
的贡献为 \(\sum a\times b_i\times c_i\) 即 \(a\sum b_i\times c_i\)。预处理 \(b_i\times c_i\) 前缀和。
这样,就可以枚举每个点然后 \(O(1)\) 计算贡献了,预处理和计算答案的复杂度均为 \(O(n^2)\)。
Code
可能稍微繁琐一点,有注释。
#include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
#define pb push_back
#define mkp make_pair
using namespace std;
using ll=long long;
using pii=pair<int,int>;
using pll=pair<ll,ll>;
using ull=unsigned long long;
inline void read(int &x){
char ch=getchar();
int r=0,w=1;
while(!isdigit(ch))w=ch=='-'?-1:1,ch=getchar();
while(isdigit(ch))r=(r<<1)+(r<<3)+(ch^48),ch=getchar();
x=r*w;
}
const int N=1007,mod=998244353;
int n,m,c,f,r[N][N],dn[N][N],sum[N][N],sum2[N][N];
char ok[N][N];
int getc(){
int ans=0;
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
if(dn[i][j]>=3&&ok[i][j]=='0')//至少3格
ans=(ans+(r[i][j]-1)*(sum[i+dn[i][j]-1][j]-sum[i+1][j])%mod)%mod;//注意顶点下方的第一个没有贡献
return ans;
}
int getf(){
int ans=0;
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
if(dn[i][j]>3&&ok[i][j]=='0')//至少4格
ans=(ans+(r[i][j]-1)*(sum2[i+dn[i][j]-2][j]-sum2[i+1][j])%mod)%mod;
return ans;
}
void init(){
memset(r,0,sizeof r);memset(dn,0,sizeof dn);
for(int i=1;i<=n;i++)for(int j=m;j>=1;j--)
r[i][j]=ok[i][j]=='1'?0:r[i][j+1]+1;//向右最多拓展几个
for(int j=1;j<=m;j++)for(int i=n;i>=1;i--)
dn[i][j]=ok[i][j]=='1'?0:dn[i+1][j]+1;//向下
//这里拓展的都包含了自己本身,所以调用时要减1
for(int j=1;j<=m;j++)for(int i=1;i<=n;i++)sum[i][j]=sum[i-1][j]+r[i][j]-1;//前缀和
for(int j=1;j<=m;j++)for(int i=1;i<=n;i++)sum2[i][j]=sum2[i-1][j]+(r[i][j]-1)*(dn[i][j]-1);
}
void solve(){
read(n);read(m);read(c);read(f);
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)cin>>ok[i][j];
init();
printf("%lld %lld\n",getc()*c,getf()*f);
}
main(){
int T,id;read(T);read(id);
while(T--)solve();
return 0;
}
标签:dn,int,sum,long,times,种花,ans,NOIP2022
From: https://www.cnblogs.com/LAK666/p/16928305.html