zoukankan      html  css  js  c++  java
  • LG5300 「GZOI2019/GXOI2019」与或和 二进制+单调栈

    问题描述

    Freda 学习了位运算和矩阵以后,决定对这种简洁而优美的运算,以及蕴含深邃空间的结构进行更加深入的研究。

    对于一个由非负整数构成的矩阵,她定义矩阵的 ( exttt{AND}) 值为矩阵中所有数二进制 ( exttt{AND(&)}) 的运算结果;定义矩阵的 ( exttt{OR}) 值为矩阵中所有数二进制 ( exttt{OR(|)}) 的运算结果。

    给定一个 (N imes N) 的矩阵,她希望求出:

    1. 该矩阵的所有子矩阵的 ( exttt{AND}) 值之和(所有子矩阵 ( exttt{AND}) 值相加的结果)。
    2. 该矩阵的所有子矩阵的 ( exttt{OR}) 值之和(所有子矩阵 ( exttt{OR}) 值相加的结果)。

    接下来的剧情你应该已经猜到——Freda 并不想花费时间解决如此简单的问题,所以这个问题就交给你了。

    由于答案可能非常的大,你只需要输出答案对 (1,000,000,007 (10^9 + 7)) 取模后的结果。

    LG5300


    题解

    发现 and 和 or 大毒瘤出现开幕雷击,于是考虑按位计算贡献。

    问题就简化为了01矩阵。

    于是一个子矩阵全是0的话对or有负贡献,全是1的话对and有正贡献。

    单调栈维护即可


    (mathrm{Code})

    #include<bits/stdc++.h>
    using namespace std;
    
    #define int long long
    
    template <typename Tp>
    void read(Tp &x){
    	x=0;char ch=1;int fh=1;
    	while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
    	if(ch=='-') ch=getchar(),fh=-1;
    	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    	x*=fh;
    }
    
    const int mod=1000000007;
    const int maxn=1007;
    
    int a[maxn][maxn],n;
    long long ansor,ansand;
    int s[maxn],h[maxn],val[maxn],pos;
    int mx;
    
    void Init(void){
    	read(n);
    	for(int i=1;i<=n;i++) for(int j=1;j<=n;j++)
    		read(a[i][j]),mx=max(mx,a[i][j]);
    }
    
    long long sqr(long long x){
    	return (long long)x*(x+1)/2;
    }
    
    int calc(int need){
    	long long res=0;
    	memset(h,0,sizeof(h));
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=n;j++){
    			if((a[i][j]&1)==need) h[j]++;
    			else h[j]=0;
    			if(h[j]>s[pos]) s[++pos]=h[j],val[pos]=1;
    			else{
    				int k=0;
    				while(h[j]<s[pos]){
    					k+=val[pos];
    					res=(res+(s[pos]-max(s[pos-1],h[j]))*sqr(k)%mod)%mod;
    					--pos;
    				}
    				s[++pos]=h[j],val[pos]=k+1;
    			}
    		}
    		int k=0;
    		while(pos){
    			k+=val[pos];
    			res=(res+(s[pos]-s[pos-1])*sqr(k)%mod)%mod;
    			--pos;
    		}
    	}
    	return res;
    }
    
    void Work(void){
    	int tp=0;
    	while(mx){
    		ansand=(ansand+calc(1)*(1<<tp)%mod)%mod;
    		ansor=(ansor+(sqr(n)*sqr(n)%mod-calc(0))*(1<<tp)%mod)%mod;
    		mx>>=1;tp++;
    		for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) a[i][j]>>=1;
    	}
    	ansand=(ansand%mod+mod)%mod;
    	ansor=(ansor%mod+mod)%mod;
    	printf("%lld %lld
    ",ansand,ansor);
    }
    
    signed main(){
    //	freopen("andorsum.in","r",stdin);freopen("andorsum.out","w",stdout);
    	Init();
    	Work();
    }
    
  • 相关阅读:
    linux gcc安装
    重装win7后如何恢复ubuntu引导
    Eclipse搭建Android开发环境(安装ADT,Android4.4.2)
    mysql变量使用总结
    最快得到MYSQL两个表的差集
    mysqldb
    更改时间 (时分秒)
    使用命令转移文件
    报喜啦~过了!
    Jmeter接口测试示例
  • 原文地址:https://www.cnblogs.com/liubainian/p/12181424.html
Copyright © 2011-2022 走看看