zoukankan      html  css  js  c++  java
  • 【BZOJ5502】[GXOI/GZOI2019]与或和(单调栈)

    【BZOJ5502】[GXOI/GZOI2019]与或和(单调栈)

    题面

    BZOJ
    洛谷

    题解

    看到位运算就直接拆位,于是问题变成了求有多少个全(0)子矩阵和有多少个全(1)子矩阵。
    这两个操作本质就是一样的,不妨考虑有多少个全(1)子矩阵。
    预处理出每个元素向上能够找的最多的(1)的个数,对于每一行从做往右扫一遍,拿一个单调栈维护一下,这样子就可以计算出以每个元素为右下角时的贡献了。
    时间复杂度(O(n^2logV)),在BZOJ上因为常数太大T了QwQ。

    #include<iostream>
    #include<cstdio>
    using namespace std;
    #define MAX 1010
    #define MOD 1000000007
    inline int read()
    {
    	int x=0;bool t=false;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=true,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return t?-x:x;
    }
    int n,a[MAX][MAX],b[MAX][MAX],u[MAX][MAX];
    int Q[MAX],h,t,ans1=0,ans2=0;
    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)b[i][j]=(a[i][j]>>k)&1;
    		for(int i=1;i<=n;++i)
    			for(int j=1;j<=n;++j)
    				if(!b[i][j])u[i][j]=0;
    				else u[i][j]=u[i-1][j]+1;
    		for(int i=1;i<=n;++i)
    		{
    			Q[h=t=1]=0;int now=0;
    			for(int j=1;j<=n;++j)
    			{
    				while(h<t&&u[i][Q[t]]>=u[i][j])now=(now+MOD-1ll*(Q[t]-Q[t-1])*u[i][Q[t]]%MOD)%MOD,--t;
    				now=(now+1ll*(j-Q[t])*u[i][j])%MOD;Q[++t]=j;
    				ans1=(ans1+1ll*now*(1<<k))%MOD;
    			}
    		}
    		for(int i=1;i<=n;++i)
    			for(int j=1;j<=n;++j)b[i][j]^=1;
    		for(int i=1;i<=n;++i)
    			for(int j=1;j<=n;++j)
    				if(!b[i][j])u[i][j]=0;
    				else u[i][j]=u[i-1][j]+1;
    		ans2=(ans2+1ll*(1<<k)%MOD*(1ll*n*(n+1)/2*n*(n+1)/2%MOD)%MOD)%MOD;
    		for(int i=1;i<=n;++i)
    		{
    			Q[h=t=1]=0;int now=0;
    			for(int j=1;j<=n;++j)
    			{
    				while(h<t&&u[i][Q[t]]>=u[i][j])now=(now+MOD-1ll*(Q[t]-Q[t-1])*u[i][Q[t]]%MOD)%MOD,--t;
    				now=(now+1ll*(j-Q[t])*u[i][j])%MOD;Q[++t]=j;
    				ans2=(ans2+MOD-1ll*now*(1<<k)%MOD)%MOD;
    			}
    		}
    		continue;
    	}
    	printf("%d %d
    ",ans1,ans2);
    	return 0;
    }
    
  • 相关阅读:
    Python基础知识
    Oracle 总结
    Linux基本命令
    测试理论
    计算机基础
    http常见的状态码,400,401,403状态码分别代表什么?
    html
    day21 包
    day20 模块引入的一些说明
    我又回来了???
  • 原文地址:https://www.cnblogs.com/cjyyb/p/10729836.html
Copyright © 2011-2022 走看看