[GXOI/GZOI2019]与或和 Posted on 2019-09-22 | In 题解 一日双更休闲至极 考虑对矩阵中的数按二进制位计算贡献 对于$AND$运算,只有全$1$子矩阵有贡献 对于$OR$运算,只有全$0$子矩阵没有贡献 可以用单调栈做到$O(n^2)$计算贡献 1234567891011121314151617181920212223242526272829303132333435363738394041#include<bits/stdc++.h>#define mod 1000000007using namespace std;int a[1001][1001],b[1001][1001],u[1001][1001],high[1001],wide[1001];inline long long clac (int n) { register long long sum=0,top=0,res=0; for(register int i=1;i<=n;++i) { for(register int j=1;j<=n;++j) { u[i][j]=(b[i][j])?u[i-1][j]+1:0; register long long w=1,h=u[i][j]; while(top&&h<=high[top]) sum-=high[top]*wide[top],w+=wide[top--]; high[++top]=h,wide[top]=w; sum+=w*h; res+=sum; } sum=top=0; } return res%mod;}inline int read () { char ch=getchar(); register int num=0; while(!isdigit(ch)) ch=getchar(); while(isdigit(ch)) num=(num<<3)+(num<<1)+(ch^'0'),ch=getchar(); return num;}int main () { register int n=read(),m=(n+1)*n/2; for(register int i=1;i<=n;++i) for(register int j=1;j<=n;++j) a[i][j]=read(); register long long g=0,f=0,num=(long long)m*m%mod; for(register int k=0;k<32;++k) { for(register int i=1;i<=n;++i) for(register int j=1;j<=n;++j) b[i][j]=(a[i][j]>>k)&1; (f+=clac(n)*(1<<k)%mod)%=mod; for(register int i=1;i<=n;++i) for(register int j=1;j<=n;++j) b[i][j]^=1; (g+=(num-clac(n)+mod)*(1<<k)%mod)%=mod; } printf("%lld %lld\n",f,g); return 0;}