联考20200612 T1 「雅礼集训 2018 Day11」进攻!

题目传送门

分析:
我们考虑求最终交集恰好为某个矩形的答案
发现这玩意不好求,我们退而求其次
求最终交集包含某个矩形的答案
这个就可以做了,考虑一个全1矩形贡献范围为给一个矩形内部+1,差分一下变成两个角+1,两个角-1
差分后的贡献可以转化为一个全1矩形对左上右上左下右下的贡献,这个做四次单调栈DP就好了
一个\(n*m\)的矩形会被他内部:
\(1*1\)的矩形算\(n*m\)次
\(1*2\)的矩形算\(n*(m-1)\)次
\(2*1\)的矩形算\((n-1)*m\)次
\(2*2\)的矩形算\((n-1)*(m-1)\)次
发现\(n*m+(n-1)*(m-1)-n*(m-1)-(n-1)*m=1\)这个矩形就只被算一次了
于是我们求最终交集包含的矩形的答案,只需要求得大小为\(1*1,1*2,2*1,2*2\)的矩形的答案就好了
复杂度\(O(n^2logK)\)

#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
#include<queue>
#include<map>

#define maxn 2005
#define INF 0x3f3f3f3f
#define MOD 998244353

using namespace std;

inline int getint()
{
	int num=0,flag=1;char c;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
	return num*flag;
}

int n,m,K;
char s[maxn][maxn];
long long f[4][maxn][maxn],g[maxn][maxn];
int sum[maxn][maxn];
long long ans;
int stk[maxn],tp;

inline long long ksm(long long num,long long k)
{
	long long ret=1;
	for(;k;k>>=1,num=num*num%MOD)if(k&1)ret=ret*num%MOD;
	return ret;
}

inline void solve()
{
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)sum[i][j]=(s[i][j]-48)?sum[i-1][j]+1:0;
	for(int i=1;i<=n;i++)for(int j=1,cnt=tp=0;j<=m;j++)
	{
		while(tp&&sum[i][stk[tp]]>=sum[i][j])cnt-=sum[i][stk[tp]]*(stk[tp]-stk[tp-1]),--tp;
		cnt+=sum[i][j]*(j-stk[tp]);
		g[i][j]=cnt,stk[++tp]=j;
	}
}

int main()
{
	n=getint(),m=getint(),K=getint();
	for(int i=1;i<=n;i++)scanf("%s",s[i]+1);
	
	solve();
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
	{
		f[0][i+1][j+1]+=g[i][j];
		f[1][i][j+1]+=g[i][j];
		f[2][i+1][j]+=g[i][j];
		f[3][i][j]+=g[i][j];
	}
	
	for(int i=1;i<=n;i++)reverse(s[i]+1,s[i]+m+1);
	solve();
	for(int i=1;i<=n;i++)reverse(g[i]+1,g[i]+m+1);
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
	{
		f[0][i+1][j]-=g[i][j];
		f[1][i][j]-=g[i][j];
		f[2][i+1][j]-=g[i][j];
		f[3][i][j]-=g[i][j];
	}
	
	reverse(s+1,s+n+1);
	solve();
	reverse(g+1,g+n+1);
	for(int i=1;i<=n;i++)reverse(g[i]+1,g[i]+m+1);
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
	{
		f[0][i][j]+=g[i][j];
		f[1][i][j]+=g[i][j];
		f[2][i][j]+=g[i][j];
		f[3][i][j]+=g[i][j];
	}
	
	for(int i=1;i<=n;i++)reverse(s[i]+1,s[i]+m+1);
	solve();
	reverse(g+1,g+n+1);
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
	{
		f[0][i][j+1]-=g[i][j];
		f[1][i][j+1]-=g[i][j];
		f[2][i][j]-=g[i][j];
		f[3][i][j]-=g[i][j];
	}
	
	for(int k=0;k<4;k++)
		for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
			f[k][i][j]=f[k][i][j]-f[k][i-1][j-1]+f[k][i-1][j]+f[k][i][j-1];
	for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
	{
		ans=(ans+ksm(f[0][i][j]%MOD,K))%MOD;
		ans=(ans-ksm(f[1][i][j]%MOD,K))%MOD;
		ans=(ans-ksm(f[2][i][j]%MOD,K))%MOD;
		ans=(ans+ksm(f[3][i][j]%MOD,K))%MOD;
	}
	printf("%lld\n",(ans+MOD)%MOD);
}

联考20200612 T1 「雅礼集训 2018 Day11」进攻!

上一篇:头文件的创建和引用


下一篇:TCP连接客户端的方法