zoukankan      html  css  js  c++  java
  • LOJ#3083.「GXOI / GZOI2019」与或和_单调栈_拆位

    #3083. 「GXOI / GZOI2019」与或和

    题目大意

    给定一个(N imes N)的矩阵,求所有子矩阵的(AND(&))之和、(OR(|))之和。

    数据范围

    (1le Nle 10^3)(val_{(i,j)} le 2^{31}-1)

    题解

    一眼题。

    对于这种位运算的题,题都不用看完先想拆位,拆位可行那就拆,拆位不可行就不拆。

    这里指的拆位可不可行具体指的是答案满不满足对于拆位之后的可加性。

    发现这个题所求的是个和,那就果断拆开。

    这样的话问题就变成了给定一个(01)矩阵求(AND)和((OR)同理)。

    发现只要是子矩阵中有(0)就是(0)

    这种存在即可的式子最(gay)了。

    绝大多数这种存在即可的式子都会依照“正难则反”变成“不存在即可”。

    故此我们只需要求全(1)子矩阵个数。

    这就很好求了,给定一个边长最多是(1000)的正方形(01)矩阵,问全(1)子矩阵个数。

    每一行拿单调栈扫一扫就好了。

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    #define N 1010 
    int ori[N][N],a[N][N],bfr_up[N][N],bfr[N],aft[N],q[N],top;
    int bin[31];
    const int mod = 1000000007 ;
    const int inv4 = 250000002 ;
    char *p1,*p2,buf[1000000];
    #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++)
    int rd() {int x=0; char c=nc(); while(c<48) c=nc(); while(c>47) x=(((x<<2)+x)<<1)+(c^48),c=nc(); return x;}
    int main()
    {
    	bin[0]=1; for(int i=1;i<=30;i++) bin[i]=bin[i-1]<<1;
    	int n=rd();
    	for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) ori[i][j]=rd();
    	int ans1=0,ans2=0;
    	for(int bt=0;bt<=30;bt++)
    	{
    		int now1=0,now2=0;
    		for(int i=1;i<=n;i++) for(int j=1;j<=n;j++)
    		{
    			a[i][j]=(ori[i][j]>>bt)&1;
    			if(a[i][j]) bfr_up[i][j]=bfr_up[i-1][j]+1; else bfr_up[i][j]=0;
    		}
    		for(int i=1;i<=n;i++)
    		{
    			top=0;
    			for(int j=n;j;j--)
    			{
    				while(top&&bfr_up[i][j]<bfr_up[i][q[top]]) bfr[q[top]]=j,top--;
    				q[++top]=j;
    			}
    			while(top) bfr[q[top]]=0,top--;
    			top=0;
    			for(int j=1;j<=n;j++)
    			{
    				while(top&&bfr_up[i][j]<=bfr_up[i][q[top]]) aft[q[top]]=j,top--;
    				q[++top]=j;
    			}
    			while(top) aft[q[top]]=n+1,top--;
    			for(int j=1;j<=n;j++) (now1+=(ll)bfr_up[i][j]*(aft[j]-j)*(j-bfr[j])%mod)%=mod;
    		}
    		for(int i=1;i<=n;i++) for(int j=1;j<=n;j++)
    		{
    			a[i][j]^=1;
    			if(a[i][j]) bfr_up[i][j]=bfr_up[i-1][j]+1; else bfr_up[i][j]=0;
    		}
    		for(int i=1;i<=n;i++)
    		{
    			top=0;
    			for(int j=n;j;j--)
    			{
    				while(top&&bfr_up[i][j]<bfr_up[i][q[top]]) bfr[q[top]]=j,top--;
    				q[++top]=j;
    			}
    			while(top) bfr[q[top]]=0,top--;
    			top=0;
    			for(int j=1;j<=n;j++)
    			{
    				while(top&&bfr_up[i][j]<=bfr_up[i][q[top]]) aft[q[top]]=j,top--;
    				q[++top]=j;
    			}
    			while(top) aft[q[top]]=n+1,top--;
    			for(int j=1;j<=n;j++) (now2+=(ll)bfr_up[i][j]*(aft[j]-j)*(j-bfr[j])%mod)%=mod;
    		}
    		now1=(ll)now1*bin[bt]%mod;
    		now2=(ll)now2*bin[bt]%mod;
    		(ans1+=now1)%=mod;
    		(ans2+=((ll)n * n * (n + 1) * (n + 1) % mod * inv4 % mod * bin[bt] % mod-now2 + mod)%mod)%=mod;
    	}
    	printf("%d %d
    ",ans1,ans2);
    	return 0;
    }
    
    

    小结

    模拟赛中被卡常了,(LOJ)也被卡常了。

    这种取(mod)的题少取两次(mod)就好了。

  • 相关阅读:
    python生成随机密码
    python计算md5值
    python---连接MySQL第五页
    python---连接MySQL第四页
    梯度下降(Gradient Descent)小结
    矩阵的线性代数意义
    矩阵的意义
    偏导数与全导数的关系 以及 偏微分与全微分的关系
    mysql-blog
    python及numpy,pandas易混淆的点
  • 原文地址:https://www.cnblogs.com/ShuraK/p/10758252.html
Copyright © 2011-2022 走看看