題解: [GXOI/GZOI2019]與或和

我們考慮簡化題意:

由於與運算和或運算在每一位上都是獨立的,我們可以考慮對每一位進行計算。

子任務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;
} 

  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章