题解 P5300 【[GXOI/GZOI2019]与或和】
测试一开始看错题目敲了两小时,发现是个水题
目前是洛咕rk1 (开了O2的那种)
做法较为玄学,没有单调栈 因为不会
首先把
显然对于某一二进制位,我们需要求出此位
枚举每一个位置作为右下角,记
因为后缀
时间效率
而且代码很短的就0.7k
#include<cstdio>
#define L long long
const L p=1e9+7,N=1002,u=(1ll<<31)-1;
L n,a[N][N],s[N],v[N],r[N],A,O;
inline L S(L k) {
L c=0;for(L j=1;j<=n;j++) s[j]=r[j]=0;
for(L i=1;i<=n;i++)
for(L j=1,w=0;j<=n;j++) {
if(a[i][j]>>k&1) s[j]=i,r[w=j]=0;
else if(w>r[j]) r[j]=w;
v[j]=v[r[j]]+s[j]*(j-r[j]);
c+=v[j];if(c>=p) c-=p;
}return c*(1ll<<k)%p;
}
int main() {
scanf("%lld",&n);
for(L i=1;i<=n;i++) for(L j=1;j<=n;j++)
scanf("%lld",&a[i][j]);
for(L i=0;i<=30;i++) if((O+=S(i))>=p) O-=p;
for(L i=1;i<=n;i++) for(L j=1;j<=n;j++) {
a[i][j]^=u;if((A+=i*j*u%p)>=p) A-=p;
}
for(L i=0;i<=30;i++) if((A-=S(i))<0) A+=p;
return printf("%lld %lld\n",A,O),0;}