习题:与或和(单调栈)
作者:互联网
题目
思路
因为与位运算有关
所以第一点可以想到是算包含每一位的有哪些矩阵
有了这一个思路之后
问题可以分为两个子问题
问题1:如何求&
对于一个矩阵,如果我们假设这个矩阵的&值的二进制第k位为1
那么其中的每一个数的二进制的第k位都为1
有了这个之后,直接单调栈怼上去就行了
问题2:如何求|
如果采用和求&一样的方式去思考
我们发现如果这个矩阵的|值得二进制第k位为1
那么矩阵中至少有一个数的二进制第k位为1
但是我们发现这个东西不好直接求
但是你可以用全部的矩阵数量减去不合条件的矩阵
也就是说,
减去的不合条件的矩阵其实就是&值的二进制的第k位为0的矩阵
一样的单调栈怼上去就行了
代码
#include<iostream>
#include<cstdio>
using namespace std;
const int mod=1e9+7;
long long n;
long long s_top;
long long st[1005];
long long h[1005];
long long w[1005];
long long a[1005][1005];
long long ans_and;
long long ans_or;
long long solve_sum(long long limt)
{
return limt*(limt+1)/2;
}
long long solve(int bj)
{
long long tot=0;
for(int i=1;i<=n;i++)
h[i]=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if((a[i][j]&1)==bj)
h[j]++;
else
h[j]=0;
if(h[j]>st[s_top])
{
st[++s_top]=h[j];
w[s_top]=1;
}
else
{
long long wid=0;
while(st[s_top]>h[j])
{
wid+=w[s_top];
tot=(tot+(st[s_top]-max(st[s_top-1],h[j]))*solve_sum(wid))%mod;
s_top--;
}
st[++s_top]=h[j];
w[s_top]=wid+1;
}
}
long long wid=0;
while(s_top)
{
wid+=w[s_top];
tot=(tot+(st[s_top]-st[s_top-1])*solve_sum(wid))%mod;
s_top--;
}
}
return tot;
}
void dfs(int dep)
{
if(dep==32)
return;
ans_and=(ans_and+solve(1)*(1ll<<dep))%mod;
ans_or=(ans_or+(solve_sum(n)*solve_sum(n)%mod-solve(0))*(1ll<<dep))%mod;
//cout<<solve(1)<<' '<<solve(0)<<'\n';
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
a[i][j]>>=1;
dfs(dep+1);
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>a[i][j];
dfs(0);
cout<<(ans_and+mod)%mod<<' '<<(ans_or+mod)%mod;
return 0;
}
标签:wid,top,矩阵,long,st,tot,习题,单调 来源: https://www.cnblogs.com/loney-s/p/12038988.html