題解:YNOI/GZOI2019 與或和

題目大意:

1. 求所有的子矩陣的and之和
2. 求所有子矩陣的or之和

由於是位運算,那麼久直接拆位,於是就變成了求全0子矩陣的個數和全1子矩陣的個數
那麼題目就變成了簡單的單調棧問題

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
using namespace std;

#define re register
#define ll long long
#define gc getchar()
inline int read()
{
 	re int x(0),f(1);re char c(gc);
    while(c>'9'||c<'0')f=c=='-'?-1:1,c=gc;
    while(c>='0'&&c<='9')x=x*10+c-48,c=gc;
    return f*x;
}

const int N=1010,mod=1e9+7;
int n,a[N][N],h[N][N],top,s[N];
ll ans;

int main()
{
	n=read();
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
			a[i][j]=read(); 
	for(int k=0;k<=31;++k)
	{
		for(int i=1;i<=n;++i)
			for(int j=1;j<=n;++j)
			{
				if((a[i][j]>>k)&1)
					h[i][j]=h[i-1][j]+1;
				else
					h[i][j]=0;
			}
		for(int i=1;i<=n;++i)
		{
			ll an(0);top=0;
			for(int j=1;j<=n;++j)
			{
				an+=h[i][j];
				while(top&&h[i][s[top]]>=h[i][j])
					an-=(s[top]-s[top-1])*(h[i][s[top--]]-h[i][j]);
				ans+=an<<k;
				ans%=mod;
				s[++top]=j;
			}
		}
	} 
	cout<<ans<<" ";
	ans=0,top=0;
	memset(s,0,sizeof(s));
	for(int k=0;k<=31;++k)
	{
		for(int i=1;i<=n;++i)
			for(int j=1;j<=n;++j)
			{
				if((a[i][j]>>k)&1)
					h[i][j]=0;
				else
					h[i][j]=h[i-1][j]+1;
			}
		for(int i=1;i<=n;++i)
		{
			ll an(0);top=0;
			for(int j=1;j<=n;++j)
			{
				an+=h[i][j];
				while(top&&h[i][s[top]]>=h[i][j])
					an-=(s[top]-s[top-1])*(h[i][s[top--]]-h[i][j]);
				ans+=(1LL*i*j-an)<<k;
				ans%=mod;
				s[++top]=j;
			}
		}
	} 
	cout<<ans<<" ";
	return 0;
} 

  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章