我們考慮簡化題意:
由於與運算和或運算在每一位上都是獨立的,我們可以考慮對每一位進行計算。
子任務1是全1子矩陣
子任務2是總子矩陣個數減去全0子矩陣
然後就是單調棧原題 :洛谷 3400 倉鼠窩
#include <bits/stdc++.h> 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; }