題意:給你一個n*n(n<=1000)的矩陣,要求求出所有子矩陣的OR和 以及 所有子矩陣的AND和
題解:子矩陣的AND和 可以將矩陣的每一個元素拆成30位二進制 對於每一位二進制討論貢獻 那麼每存在一個子矩陣全是1 那麼就會對答案貢獻乘以這一位的權值 那麼這裏就設計到一個小技巧 -- 找一個矩陣全是1的子矩陣個數 不會這個知識點便立馬學習了一下 受到博客 https://blog.csdn.net/qq_42814118/article/details/81349964 的啓發, 可以枚舉每一列 然後枚舉一行 從這一行作爲矩陣的最大寬度 然後上下延伸(保持單向性防止重複) 延伸的長度乘以寬度便是這個位置的所有矩陣的貢獻 同時要事先預處理出來每一行連續1的個數 OR的和便是可以用總的個數減去全是0的子矩陣的個數然後乘以每一位的貢獻即可(卡常,注意取模的個數)
#include<bits/stdc++.h>
using namespace std;
#define Sheryang main
const int maxn=2e5+7;
typedef long long ll;
const int mod=1e9+7;
#define getchar()(p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf[(1 << 21) + 1], *p1 = buf, *p2 = buf;
#define IO cin.tie(0),ios::sync_with_stdio(false);
#define pi acos(-1)
#define PII pair<ll,ll>
ll read(){ll c = getchar(),Nig = 1,x = 0;while(!isdigit(c) && c!='-')c = getchar();if(c == '-')Nig = -1,c = getchar();while(isdigit(c))x = ((x<<1) + (x<<3)) + (c^'0'),c = getchar();return Nig*x;}
#define read read()
/** keep hungry and keep calm! **/
ll a[1005][1005],num[1005][1005];
int n,up[1005],down[1005],st[1005];
ll calc(int v){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
num[i][j] = ((a[i][j]&1)==v)?num[i][j-1]+1:0;
}
}
ll sum = 0;
int top = 0;
for(int j=1;j<=n;j++){
top = 0;
for(int i=1;i<=n;i++){
if(num[i][j]){
up[i] = 1;
while(top && num[i][j]<num[st[top]][j]) up[i]+=up[st[top--]]; // 單調棧維護 然後合併
st[++top] = i;
}else{
top = 0;
up[i] = 0;
}
}
top = 0;
for(int i=n;i>=1;i--){
if(num[i][j]){
down[i] = 1;
while(top && num[i][j]<=num[st[top]][j]) down[i]+=down[st[top--]]; //延伸時保持單向性 與上面不一致即可
st[++top] = i;
}else{
top = 0;
down[i] = 0;
}
sum += 1LL*up[i]*down[i]*num[i][j]%mod;
if(sum>=mod) sum -= mod;
}
}
return sum;
}
int Sheryang(){
n = read;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
a[i][j] = read;
}
}
ll ans1 = 0,ans2 = 0;
ll tot = 1LL*n*(n+1)/2*n*(n+1)/2%mod;//總矩陣的個數
for(int i=0,tmp=1;i<31;i++,tmp<<=1){
ans1 += calc(1)*tmp%mod;
if(ans1>=mod) ans1 -= mod;
ans2 += (tot-calc(0)%mod+mod)%mod*tmp%mod;
if(ans2>=mod) ans2 -= mod;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
a[i][j] >>= 1;
}
}
}
printf("%lld %lld\n",ans1,ans2);
return 0;
}