zoukankan      html  css  js  c++  java
  • 【bzoj4750】密码安全 单调栈

    题目描述

    模10^9+61

    输入

    第一行包含一个正整数 T ,表示有 T 组测试数据。
    接下来依次给出每组测试数据。对于每组测试数据:
    第一行包含一个正整数 n 。
    第二行包含 n 个非负整数,表示 A_1,A_2,?,A_n 。
    保证在一行中的每个整数之间有恰好一个空格,没有其他额外的空格。
    100% 的数据满足:1≤T≤200,1≤n≤10^5,1≤∑n≤10^6,0≤A_i≤10^9

    输出

    对于每组数据输出一行,包含一个整数,表示答案对10^9+61 取模的值。

    样例输入

    3
    1
    61
    5
    1 2 3 4 5
    5
    10187 17517 24636 19706 18756

    样例输出

    3721
    148
    821283048


    题解

    单调栈

    区间异或和比较容易处理,关键在于区间最大值

    考虑一个数作为最大值的贡献:使用单调栈处理出一个数左边第一个大于等于它的数的位置lp和右边第一个大于它的数的位置rp。那么该数的贡献为:左端点[lp[i]+1,i],右端点[i,rp[i]-1]。

    然后再考虑异或和:区间异或和可以由前缀异或来表示。所以满足条件的区间的异或相当于suml在[lp[i],i-1],sumr在[i,rp[i]-1]的两个数的异或。

    我们可以拆位,然后对于前缀异或和的某一位维护前缀1的个数。如果该为异或为1,则说明左边为1,右边为0或左边为0,右边为1。分别把方案数计算出来即可。

    注意在计算suml所在区间的前缀相减时lp[i]-1可能为负数,因此需要把数组下标平移1位处理。

    #include <cstdio>
    #include <cstring>
    #define N 100010
    #define mod 1000000061
    typedef long long ll;
    int a[N] , sum[N] , c[N][30] , lp[N] , rp[N] , sta[N] , tot;
    int main()
    {
    	int T;
    	scanf("%d" , &T);
    	while(T -- )
    	{
    		int n , i , j , ans = 0;
    		scanf("%d" , &n);
    		memset(c , 0 , sizeof(c));
    		for(i = 2 ; i <= n + 1 ; i ++ )
    		{
    			scanf("%d" , &a[i]) , sum[i] = sum[i - 1] ^ a[i];
    			for(j = 0 ; j < 30 ; j ++ ) c[i][j] = c[i - 1][j] + (bool)(sum[i] & (1 << j));
    		}
    		tot = 0 , sta[0] = 1;
    		for(i = 2 ; i <= n + 1 ; i ++ )
    		{
    			while(tot && a[sta[tot]] < a[i]) tot -- ;
    			lp[i] = sta[tot] , sta[++tot] = i;
    		}
    		tot = 0 , sta[0] = n + 2;
    		for(i = n + 1 ; i >= 2 ; i -- )
    		{
    			while(tot && a[sta[tot]] <= a[i]) tot -- ;
    			rp[i] = sta[tot] , sta[++tot] = i;
    		}
    		for(i = 2 ; i <= n + 1 ; i ++ )
    			for(j = 0 ; j < 30 ; j ++ )
    				ans = (ans + ((ll)(c[i - 1][j] - c[lp[i] - 1][j]) * (rp[i] - i - c[rp[i] - 1][j] + c[i - 1][j])
    				           + (ll)(i - lp[i] - c[i - 1][j] + c[lp[i] - 1][j]) * (c[rp[i] - 1][j] - c[i - 1][j])) % mod
    				           * (1 << j) % mod * a[i]) % mod;
    		printf("%d
    " , ans);
    	}
    	return 0;
    }
    

     

  • 相关阅读:
    hive 修复分区、添加二级分区
    hive sql 查询一张表的数据不在另一张表中
    shell 命令 bc linux下的计算器
    shell 命令 grep -v
    shell 命令 -- 漂亮的资源查看命令 htop
    shell 命令 --ps aux | grep
    presto调研和json解析函数的使用
    shell wc -l
    hive 动态分区与混合分区
    ThreadLocal原理分析与使用场景(转)
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7660204.html
Copyright © 2011-2022 走看看