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

    又是GXOI2019里水水的送分题,然而我看错题+细节写挂愣是搞了一个多小时(深深的明白自己的弱小)

    首先看到二进制我们就考虑到枚举每一位,算子矩阵中这一位为(1)的方案数再乘起来吧

    然后这时候矩阵就变成了(0/1)矩阵(其实样例1就在提示你这种做法),我们考虑(operatorname{AND})时的答案,即求出(1)矩阵个数

    这个很套路吧,我们预处理出(h_{i,j})表示((i,j))以上(包括((i,j))最多有多少个连续的(1)

    接下来考虑求出以每一个点为矩阵的右下角时的方案数,每一列的情况可以单调栈处理:

    考虑连续递增的一段的答案(如((3,5,6))我们是可以计算的,就是一个求和的过程),那么我们就维护单调递增的单调栈

    然后考虑每次加入一个数,那么前面大于它的都会被他删掉,此时的贡献其实就是删掉数的个数( imes)当前的(h_{i,j})

    因此单调栈里再维护一下前缀和以及数的个数(因为被删除的要累积到删除它的数上),就完成了(operatorname{AND})的做法

    那么(operatorname{OR})呢,其实直接补集转化一下就好了,用总方案数减去全(0)矩阵方案数即为所求

    因此综上,复杂度(O(n^2log a_i)),足以通过此题

    CODE

    #include<cstdio>
    #include<cctype>
    #define RI register int
    #define CI const int&
    #define Tp template <typename T>
    using namespace std;
    const int N=1005,mod=1e9+7;
    int n,a[N][N],and_ans,or_ans,mx,h[N][N],st[N],sum[N],val[N],top,cur;
    class FileInputOutput
    {
    	private:
    		static const int S=1<<21;
    		#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
    		char Fin[S],*A,*B;
    	public:
    		Tp inline void read(T& x)
    		{
    			x=0; char ch; while (!isdigit(ch=tc()));
    			while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
    			
    		}
    		#undef tc
    }F;
    inline void inc(int& x,CI y)
    {
    	if ((x+=y)>=mod) x-=mod;
    }
    inline int add(CI x,CI y)
    {
    	int t=x+y; return t>=mod?t-mod:t;
    }
    inline int solve_and(CI bs,int ret=0)
    {
    	RI i,j; for (i=1;i<=n;++i) for (j=1;j<=n;++j)
    	if (a[i][j]&bs) h[i][j]=h[i-1][j]+1; else h[i][j]=0;
    	for (i=1;i<=n;++i) for (top=0,j=1;j<=n;++j) if (!h[i][j]) top=0; else
    	{
    		int high=1; while (top&&st[top]>h[i][j]) high+=val[top--];
    		inc(ret,1LL*h[i][j]*high%mod); inc(ret,sum[top]); st[++top]=h[i][j];
    		val[top]=high; sum[top]=add(sum[top-1],1LL*h[i][j]*val[top]%mod);
    	}
    	return 1LL*ret*bs%mod;
    }
    inline int solve_or(CI bs,int ret=0)
    {
    	RI i,j; for (i=1;i<=n;++i) for (j=1;j<=n;++j)
    	if (!(a[i][j]&bs)) h[i][j]=h[i-1][j]+1; else h[i][j]=0;
    	for (i=1;i<=n;++i) for (top=0,j=1;j<=n;++j) if (!h[i][j]) top=0; else
    	{
    		int high=1; while (top&&st[top]>h[i][j]) high+=val[top--];
    		inc(ret,1LL*h[i][j]*high%mod); inc(ret,sum[top]); st[++top]=h[i][j];
    		val[top]=high; sum[top]=add(sum[top-1],1LL*h[i][j]*val[top]%mod);
    	}
    	ret=cur-ret; if (ret<0) ret+=mod; return 1LL*ret*bs%mod;
    }
    int main()
    {
    	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    	RI i,j; for (F.read(n),i=1;i<=n;++i) for (j=1;j<=n;++j)
    	F.read(a[i][j]),mx=a[i][j]>mx?a[i][j]:mx,inc(cur,1LL*i*j%mod);
    	for (i=1;i<=mx&&i>0;i<<=1) inc(and_ans,solve_and(i)),inc(or_ans,solve_or(i));
    	return printf("%d %d",and_ans,or_ans),0;
    }
    
  • 相关阅读:
    ES集群性能调优链接汇总
    【转】dmesg 时间转换
    广师大笔记汉诺塔
    广师大python学习笔记求派的值
    155. 最小栈(c++)
    160. 相交链表(c++)
    论文 数据集总结
    论文阅读 总结 复习
    121. 买卖股票的最佳时机(c++)
    9. 回文数(c++)
  • 原文地址:https://www.cnblogs.com/cjjsb/p/10970055.html
Copyright © 2011-2022 走看看