背景:
luogu
\text{luogu}
luogu崩
ing..
\text{ing..}
ing..
不知道为什么
loj
\text{loj}
loj上的
C++(NOI)
\text{C++(NOI)}
C++(NOI)比
C++
\text{C++}
C++要慢,我还以为是人丑 常数大。
题目传送门:
题意:
给出一个矩阵,分别求所有子矩阵
and,or
\text{and,or}
and,or的和。
思路:
容易想到位与位之间不冲突,因此可以按位处理。
你考虑
and
\text{and}
and的情况,其实就是子矩阵全部为
1
1
1的数目;而
or
\text{or}
or其实就是总子矩阵数量
−
-
−全部为
0
0
0的子矩阵的数目。
怎么处理全部为
0
0
0或
1
1
1的子矩阵的数目。
单调队列即可。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mod 1000000007
#define I inline
#define R register
#define LL long long
using namespace std;
int n;
int d[1010][1010];
LL same[1010];
struct node{LL x,y;} sta[1010];
LL ans1=0,ans2=0;
I int read()
{
int x=0,f=1;
char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())
if(ch=='-') f=-1;
for(;ch>='0'&&ch<='9';x=(x<<3)+(x<<1)+(ch^48),ch=getchar());
return x*f;
}
I LL work(int x,int op)
{
LL ans=0;
memset(same,0,sizeof(same));
for(R int i=1;i<=n;i++)
{
int top=0;
LL sum=0;
for(R int j=1;j<=n;j++)
{
LL row=1;
same[j]=((d[i][j]>>x)&1)==op?same[j]+1:0;
while(top&&same[j]<=sta[top].x)
{
sum=(sum-sta[top].x*sta[top].y%mod+mod)%mod;
row=(row+sta[top].y)%mod;
top--;
}
sum=(sum+same[j]*row%mod)%mod;
ans=(ans+sum)%mod;
sta[++top]=(node){same[j],row};
}
}
return ans;
}
int main()
{
freopen("a.in","r",stdin);
n=read();
LL tot=((LL)(1+n)*n/2)*((LL)(1+n)*n/2)%mod;
for(R int i=1;i<=n;i++)
for(R int j=1;j<=n;j++)
d[i][j]=read();
for(R int i=0;i<=30;i++)
{
LL bin=(1<<i)%mod;
ans1=(ans1+bin*work(i,1)%mod)%mod;
ans2=(ans2+bin*((tot-work(i,0)+mod)%mod)%mod)%mod;
}
printf("%lld %lld",ans1,ans2);
}