[LOJ3083][單調棧]GXOI/GZOI2019:與或和

LOJ3083

很顯然是拆位
那麼對於and,就是統計這個01矩陣中的全1子矩陣個數
對於or,就是統計這個01矩陣中的全0子矩陣個數,再用全集減去它
統計01矩陣的全1子矩陣個數就直接上單調棧即可
大致做法:
記錄矩陣內每一個點上方的連續1有多少個(包括自身)
掃描每一行,求出以每個點爲右下角的矩陣的個數,可以用單調棧彈掉不合法的答案

Code:

#include<bits/stdc++.h>
#define mod 1000000007
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
inline int add(int x,int y){x+=y;if(x>=mod) x-=mod;return x;}
inline int dec(int x,int y){x-=y;if(x<0) x+=mod;return x;}
inline int mul(int x,int y){return 1ll*x*y%mod;}
inline void inc(int &x,int y){x+=y;if(x>=mod) x-=mod;}
inline void Dec(int &x,int y){x-=y;if(x<0) x+=mod;}
inline void Mul(int &x,int y){x=1ll*x*y%mod;}
inline int ksm(int a,int b){int res=1;for(;b;b>>=1,a=mul(a,a)) if(b&1) res=mul(res,a);return res;}
const int N=1e3+5;
int a[N][N],s[N][N],sta[N],top;
int n,ans;
inline void calc(){
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++) s[i][j]=a[i][j]*(s[i-1][j]+1);
	for(int i=1;i<=n;i++){
		sta[top=0]=0;int res=0;
		for(int j=1;j<=n;j++){
			inc(res,s[i][j]);
			while(top && s[i][sta[top]]>=s[i][j])
				Dec(res,mul(sta[top]-sta[top-1],s[i][sta[top]]-s[i][j])),--top;
			inc(ans,res);sta[++top]=j;
		}
	}
}
int tmp[N][N],ansand=0,ansor=0;
int main(){
	n=read();
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++) tmp[i][j]=read();
	for(int d=0;d<=30;d++){
		int res=(1<<d)%mod;
		ans=0;
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++) a[i][j]=((tmp[i][j]>>d)&1);
		calc();
		inc(ansand,mul(res,ans));
		ans=0;
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++) a[i][j]^=1;
		calc();
		int tmpp=0;
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++) inc(tmpp,i*j);
		inc(ansor,mul(res,dec(tmpp,ans)));
	}
	cout<<ansand<<" "<<ansor;
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章