zoukankan      html  css  js  c++  java
  • [GXOI/GZOI2019]与或和

    嘟嘟嘟


    在GX大佬cyh的提议下,我就开了这道题。


    看到位运算,就想到每一位单独考虑。
    那么对于(AND)操作,我们只要找全是1的子矩阵个数。
    对于(OR)操作,用子矩阵总数-全0子矩阵个数即可。
    这样就有一个(O(n ^ 4 logN))(N)是值域)的做法了,可以拿到50分。
    然后我就没想出来。


    现在的瓶颈在于找全1的子矩阵。
    观察发现,对于同一列的点,如果从下往上扫,以这个点为左上角的全1子矩阵的宽一定是单调不增的,于是对于每一列,我们维护一个单调栈,同时维护栈内元素的和即可。
    复杂度(O(n ^ 2logN))

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<queue>
    #include<vector>
    #include<ctime>
    #include<assert.h>
    using namespace std;
    #define enter puts("")
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define In inline
    #define forE(i, x, y) for(int i = head[x], y; (y = e[i].to) && ~i; i = e[i].nxt)
    typedef long long ll;
    typedef double db;
    const int INF = 0x3f3f3f3f;
    const db eps = 1e-8;
    const int maxn = 1e3 + 5;
    const ll mod = 1e9 + 7;
    In ll read()
    {
    	ll ans = 0;
    	char ch = getchar(), las = ' ';
    	while(!isdigit(ch)) las = ch, ch = getchar();
    	while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
    	if(las == '-') ans = -ans;
    	return ans;
    }
    In void write(ll x)
    {
    	if(x < 0) putchar('-'), x = -x;
    	if(x >= 10) write(x / 10);
    	putchar(x % 10 + '0');
    }
    In void MYFILE()
    {
    #ifndef mrclr
    	freopen("ha.in", "r", stdin);
    	freopen("ha.out", "w", stdout);
    #endif
    }
    
    int n, a[maxn][maxn];
    
    In ll inc(ll a, ll b) {return a + b < mod ? a + b : a + b - mod;}
    
    #define pr pair<int, int>
    #define mp make_pair
    #define fir first
    #define sec second
    pr st[maxn];
    int b[maxn][maxn], rMax[maxn][maxn], top = 0;
    In ll solve(int x, bool flg)
    {
    	for(int i = 1; i <= n; ++i)
    		for(int j = 1; j <= n; ++j) b[i][j] = ((a[i][j] >> x) & 1) ^ flg;
    	for(int i = 1; i <= n; ++i)
    		for(int j = n; j; --j) rMax[i][j] = b[i][j] ? max(1, rMax[i][j + 1] + 1) : 0;
    	ll ret = 0, tot = 0;
    	for(int j = 1; j <= n; ++j)
    	{
    		tot = top = 0;
    		for(int i = n; i; --i)
    		{
    			int tp = 1;
    			while(top && st[top].fir >= rMax[i][j]) 
    			{
    				tot = inc(tot, mod - st[top].sec * st[top].fir % mod);
    				tp += st[top].sec, --top;	
    			}
    			if(rMax[i][j])
    			{
    				tot = inc(tot, tp * rMax[i][j] % mod);
    				st[++top] = mp(rMax[i][j], tp);
    				ret = inc(ret, tot);
    			}
    		}
    	}
    	return ret;
    }
    
    int main()
    {
    //	MYFILE();
    	n = read();
    	for(int i = 1; i <= n; ++i)
    		for(int j = 1; j <= n; ++j) a[i][j] = read();
    	ll tot = 0;
    	for(int i = 1; i <= n; ++i)
    		for(int j = 1; j <= n; ++j) tot = inc(tot, i * j);
    	ll ans1 = 0, ans2 = 0, tp = 1;
    	for(int x = 0; x < 31; ++x, tp = (tp << 1) % mod)
    	{
    		ans1 = inc(ans1, solve(x, 0) * tp % mod);
    		ans2 = inc(ans2, inc(tot, mod - solve(x, 1)) * tp % mod);
    	}
    	write(ans1), space, write(ans2), enter;
    	return 0;
    }
    
  • 相关阅读:
    C# Lambda表达式
    C# LINQ用法
    C# XML介绍及基本操作
    C# 装箱和拆箱
    C# 堆与栈
    C#中ref和out的区别
    C#中16进制string字符串的转16byte互转
    C#中把一个Struct结构转换成Byte[]的方法
    SqlServer中查询操作记录的方法
    asp.net中后台获取Post参数(Json)最简单的一种方法。
  • 原文地址:https://www.cnblogs.com/mrclr/p/11128639.html
Copyright © 2011-2022 走看看