• 【洛谷P5300】与或和


    题目

    题目链接:https://www.luogu.com.cn/problem/P5300
    Freda 学习了位运算和矩阵以后,决定对这种简洁而优美的运算,以及蕴含深邃空间的结构进行更加深入的研究。
    对于一个由非负整数构成的矩阵,她定义矩阵的 \(\texttt{AND}\) 值为矩阵中所有数二进制 \(\texttt{AND(\&)}\) 的运算结果;定义矩阵的 \(\texttt{OR}\) 值为矩阵中所有数二进制 \(\texttt{OR(|)}\) 的运算结果。
    给定一个 \(N \times N\) 的矩阵,她希望求出:

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

    接下来的剧情你应该已经猜到——Freda 并不想花费时间解决如此简单的问题,所以这个问题就交给你了。
    由于答案可能非常的大,你只需要输出答案对 \(1,000,000,007 (10^9 + 7)\) 取模后的结果。

    思路

    样例一提示我们在一个01矩阵内先求答案。
    我们发现,在01矩阵内,若子矩阵\(and\)起来为1,那么需要满足这个矩阵全部数字都为1。如果需要\(or\)起来为1,则需要满足这个矩阵内至少有一个位置为1,那么就可以用总矩阵个数\(-\)全为0的矩阵个数。
    也就是说,在01矩阵内,我们只要求出有多少个全为1的子矩阵和有多少个全为0的子矩阵,那么\(and\)值之和与\(or\)值之和都可求。
    显然这个是可以用单调栈在\(O(n^2)\)时间内维护的。
    那么考虑原题。我们可以将其拆分成\(log(max\{a\})\)个01矩阵来做,第\(i\)位的子矩阵个数乘上\(2^i\)即可。
    时间复杂度\(O(n^2\log n)\)

    代码

    #pragma GCC optimize("Ofast")
    #pragma GCC optimize("inline")
    #include <stack>
    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <algorithm>
    #define mp make_pair
    #define st first
    #define nd second
    using namespace std;
    typedef long long ll;
    
    const int N=1010,MOD=1e9+7,LG=30;
    int n,map[N][N],a[N][N];
    ll ans1,ans2,sum;
    
    inline int read()
    {
    	int d=0; char ch=getchar();
    	while (!isdigit(ch)) ch=getchar();
    	while (isdigit(ch)) d=(d<<3)+(d<<1)+ch-48,ch=getchar();
    	return d;
    }
    
    inline ll solve(int p,int id)
    {
    	ll cnt=0;
    	for (register int i=1;i<=n;i++)
    		for (register int j=1;j<=n;j++)
    			if (((map[i][j]&(1<<p))>0)!=id) a[i][j]=0;
    				else a[i][j]=a[i-1][j]+1;
    	for (register int i=1;i<=n;i++)
    	{
    		stack<pair<int,int> > s;
    		s.push(mp(0,0));
    		for (register int j=1;j<=n+1;j++)
    		{
    			int last=j,high;
    			while (s.size()>1 && s.top().nd>a[i][j])
    			{
    				last=s.top().st; high=s.top().nd;
    				s.pop();
    				cnt=(cnt+(high-max(s.top().nd,a[i][j]))*(1+j-last)*(j-last)/2LL)%MOD;
    			}
    			s.push(mp(last,a[i][j]));
    		}
    	}
    	return cnt;
    }
    
    int main()
    {
    	n=read();
    	for (register int i=1;i<=n;i++)
    		for (register int j=1;j<=n;j++)
    		{
    			map[i][j]=read();
    			sum=(sum+i*j)%MOD;
    		}
    	for (register int i=0;i<=LG;i++)
    	{
    		ans1=(ans1+(1LL<<i)*solve(i,1))%MOD;
    		ans2=(ans2+(1LL<<i)*(sum-solve(i,0)))%MOD;
    	}
    	printf("%lld %lld",ans1,ans2);
    	return 0;
    }
    
  • 相关阅读:
    How do I change a .txt file to a .c file?
    [CQOI2007]余数求和
    CSP-J总结&题解
    【CSP游记S】
    [LuoguP1462]通往奥格瑞玛的道路
    归并排序——逆序对
    [NOIP 2011]选择客栈
    [二分图初步]【模板】二分图匹配,匈牙利算法
    [NOIP 2018]旅行
    黑魔法师之门 (magician)-并查集
  • 原文地址:https://www.cnblogs.com/stoorz/p/12155116.html
Copyright © 2020-2023  润新知