目录
显示
题目链接
https://www.luogu.com.cn/problem/P5300
题解
考虑独立计算每个二进制位的答案。
对于 AND 值之和,即为统计整个矩阵中全为 \(1\) 的子矩阵个数,OR 值之和,则只需用整个矩阵中的子矩阵个数,减去全为 \(0\) 的矩阵个数即可。
统计一个矩阵中全 \(0/1\) 的子矩阵个数可以用单调栈解决。
对于每个二进制位,统计答案的时间复杂度为 \(O(n^2)\),总时间复杂度为 \(O(n^2 \log x)\)。
#include <cstdio>
#define MOD 1000000007
int s[1005][1005],a[1005][1005],n;
int sta[1005];
long long solve(int x,int k)
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(((a[i][j]>>k)&1)==x)s[i][j]=s[i-1][j]+1;
else s[i][j]=0;
long long ans=0;
for(int i=1;i<=n;i++)
{
long long res=0;
int top=0;
for(int j=1;j<=n;j++)
{
res+=s[i][j];
while(top&&s[i][sta[top]]>s[i][j])
{
res-=(sta[top]-sta[top-1])*(s[i][sta[top]]-s[i][j]);
top--;
}
if(x)ans=(ans+(res<<k))%MOD;
else ans=(ans+((i*j-res)<<k))%MOD;
sta[++top]=j;
}
}
return ans;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&a[i][j]);
long long ans1=0,ans2=0;
for(int k=0;k<31;k++)
{
ans1=(ans1+solve(1,k))%MOD;
ans2=(ans2+solve(0,k))%MOD;
}
printf("%d %d\n",(int)ans1,(int)ans2);
return 0;
}