(笑死我了这个都能识别关键字hhhhh我也是被审核失败过的男人了hhhh)
都说了没区别了啦!
首先我们按位处理。
所以这是一个0/1矩阵。
与操作就是求全都是1的子矩阵
或操作是求至少一个1的子矩阵
全都是1就是仓鼠窝窝头
至少一个1的话
那就是总数减去都是0的子矩阵数嘛!
总数直接公式可以,递推也可以
所以这道题就是两个仓鼠窝窝头,0.5元钱的快乐
#include<bits/stdc++.h>
using namespace std;
#define in read()
#define int long long
int in{
int cnt=0,f=1;char ch=0;
while(!isdigit(ch)){
ch=getchar();if(ch=='-')f=-1;
}
while(isdigit(ch)){
cnt=cnt*10+ch-48;
ch=getchar();
}return cnt*f;
}
int sta[1003],top;
int height[1003],mapp[1003][1003],ans[1003],sum,summ;
int mp[1003][1003];
int f[1003][1003];
const int mod=1e9+7;
int n;
int jz[34];
int add(int a,int b){
return (a+b)>=mod?(a+b-mod):(a+b);
}
int dec(int a,int b){
return (a-b)<0?(a-b+mod):(a-b);
}
int mul(int a,int b){
return a*b%mod;
}
inline void work(int x){
int sum1=0;
memset(height,0,sizeof(height));
for(register int i=1;i<=n;i++){top=0;
for(register int j=1;j<=n;j++){
if(!mp[i][j])height[j]=i;
while(top&&height[sta[top]]<height[j])top--;
sta[++top]=j;
ans[top]=add(ans[top-1],mul(i-height[j],sta[top]-sta[top-1]));
sum1=add(sum1,ans[top]);
}
}sum=add(sum,mul(sum1,jz[x]));
for(register int i=1;i<=n;i++){
for(register int j=1;j<=n;j++)mp[i][j]^=1;
}
// for(register int i=1;i<=n;i++){
// for(register int j=1;j<=n;j++)cout<<mp[i][j]<<" ";cout<<endl;
// }
sum1=0;memset(height,0,sizeof(height));
for(register int i=1;i<=n;i++){top=0;
for(register int j=1;j<=n;j++){
if(!mp[i][j])height[j]=i;
while(top&&height[sta[top]]<height[j])top--;
sta[++top]=j;
ans[top]=add(ans[top-1],mul(i-height[j],sta[top]-sta[top-1]));
sum1=add(sum1,ans[top]);
}
}
sum1=dec(f[n][n],sum1);//cout<<sum1<<endl<<endl;
summ=add(summ,mul(sum1,jz[x]));//cout<<sum<<" "<<sum1<<endl;
}
signed main(){
n=in;jz[0]=1;
for(register int i=1;i<=n;i++){
jz[i]=mul(jz[i-1],2);
for(register int j=1;j<=n;j++){
mapp[i][j]=in;
f[i][j]=add(f[i-1][j],add(f[i][j-1],dec(mul(i,j),f[i-1][j-1])));
}
}
for(register int i=0;i<=30;i++){
for(register int j=1;j<=n;j++){
for(register int k=1;k<=n;k++){
mp[j][k]=(mapp[j][k]&(1<<i))?1:0;
}
}
work(i);
}
printf("%lld %lld",sum,summ);
return 0;
}