[GZOI2019]与或和

Posted by Dispwnl on April 22, 2019

题目

题解

化简问题后就成了对$01$矩阵求最大全$0/1$子矩阵

处理出来每个点往上最长延伸长度,然后单调栈解决即可

代码

# include<iostream>
# include<cstring>
# include<cstdio>
# include<algorithm>
using namespace std;
const int N=1e3+5,mod=1e9+7;
int n,ans,ans1,mx,Top;
int st[N];
int a[N][N],l[N][N];
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
	  for(int j=1;j<=n;++j)
	    scanf("%d",&a[i][j]),mx=max(mx,a[i][j]);
	for(int x=0,sum;(1ll<<x)<=mx;++x)
	  {
	  	memset(l,0,sizeof(l));
	  	sum=0;
	  	for(int i=1;i<=n;++i,Top=0,sum=0)
	  	  for(int j=1;j<=n;++j)
	  	    {
	  	    	if(a[i][j]&(1<<x)) l[i][j]=l[i-1][j]+1;
	  	    	while(Top&&l[i][j]<=l[i][st[Top]]) (sum+=mod-1ll*(st[Top]-st[Top-1])*l[i][st[Top]]%mod)%=mod,--Top;
	  	    	(sum+=1ll*(j-st[Top])*l[i][j]%mod)%=mod,st[++Top]=j,(ans+=1ll*sum*(1<<x)%mod)%=mod;
			}
		memset(l,0,sizeof(l));
		for(int i=1;i<=n;++i,Top=0,sum=0)
	  	  for(int j=1;j<=n;++j)
	  	    {
	  	    	(ans1+=1ll*i*j*(1<<x)%mod)%=mod;
	  	    	if(!(a[i][j]&(1<<x))) l[i][j]=l[i-1][j]+1;
	  	    	while(Top&&l[i][j]<=l[i][st[Top]]) (sum+=mod-1ll*(st[Top]-st[Top-1])*l[i][st[Top]]%mod)%=mod,--Top;
	  	    	(sum+=1ll*(j-st[Top])*l[i][j]%mod)%=mod,st[++Top]=j,(ans1+=mod-1ll*sum*(1<<x)%mod)%=mod;
			}
	  }
	return printf("%d %d",ans,ans1),0;
}