zoukankan      html  css  js  c++  java
  • 「CF875D High Cry」

    题目大意

    给出一个序列 (a),求有多少子串满足子串的 (max) 严格小于子串中所有数的或值.

    分析

    显然一个子串的或者肯定是大于等于子串的 (max),那么问题就变成了要求出有多少的子串的或值等于子串的 (max).再经过简单的分析,不难发现如果子串最大值的二进制中第 (k) 位为 (0),但子串中存在某数二进制下第 (k) 位的值为 (1),那么这个子串的或值必然大于最大值(最大值与这个数的或值必然大于最大值).

    考虑对每个数计算以当前数为最大值时的不合法的子串数,即计算有多少子串的最大值在某个位置((i))时有异或值等于最大值.那么这个子串的左端点((l)),右端点((r))需要满足以下条件:

    1. (lleq ileq r)((i) 位置必须在子串中)
    2. (maxlimits_{lleq jleq r}a_j=a_llor a_{l+1}lor a_{l+2}lordotslor a_{r-2}lor a_{r-1}lor a_r=a_i)(子串的最大值等于子串的异或值等于 (a_i))

    于是可以处理出以某个数为最大值的区间以及对于某个数所不存在的二进制的位置上一次和下一次出现的位置,这样就可以通过简单计算计算出结果.

    但是如果在序列中存在多个相同的数可能会出点小问题.

    如第二个样例中的 3 3 3 3,直接计算某个数为最大值的区间会计算的结果都是 ([1,4]),但这样在后面的计算中会出问题,但 ([1,4],[2,4],[3,4],[4,4]) 就不会有问题了,所以可以强制某个数是某个区间的最大值需要满足在这个数之前(或者之后)不存在大于等于这个数的数.

    代码

    #include<bits/stdc++.h>
    #define REP(i,first,last) for(int i=first;i<=last;++i)
    #define DOW(i,first,last) for(int i=first;i>=last;--i)
    namespace IO
    //快读模板
    using namespace IO;
    using namespace std;
    const int MAXN=2e5+5;
    int n;
    int place[100];
    struct Number
    {
    	int num,left,right,l,r;//每个位置的数,这个数不存在的二进制位置上一次出现的位置,下一次出现的位置,这个为最大值的区间的左端点,右端点
    }arr[MAXN];
    int st[MAXN],top=0;
    int main()
    {
    	Read(n);
    	REP(i,1,n)
    	{
    		Read(arr[i].num);
    		arr[i].left=0;
    		arr[i].right=n+1;
    		REP(j,0,31)
    		{
    			if(arr[i].num&(1<<j))//如果这个数的二进制中存在第 j 位,那么就把第 j 位的上一次出现位置变为 i
    			{
    				place[j]=i;
    			}
    			else
    			{
    				arr[i].left=Max(arr[i].left,place[j]);//否则就与最近出现位置取更近的位置
    			}
    		}
    		while(top&&arr[st[top]].num<arr[i].num)//计算左端点时用 <,右端点用 <=(反之同理)
    		{
    			top--;
    		}
    		arr[i].l=st[top];//单调栈处理出这个数为最大值的区间的左端点(右端点同理)
    		st[++top]=i;
    	}
    	top=0;
    	REP(i,0,31)
    	{
    		place[i]=n+1;
    	}
    	DOW(i,n,1)//同理
    	{
    		REP(j,0,31)
    		{
    			if(arr[i].num&(1<<j))
    			{
    				place[j]=i;
    			}
    			else
    			{
    				arr[i].right=Min(arr[i].right,place[j]);
    			}
    		}
    		while(top&&arr[st[top]].num<=arr[i].num)
    		{
    			top--;
    		}
    		arr[i].r=st[top]?st[top]:n+1;
    		st[++top]=i;
    	}
    	long long answer=1ll*n*(n+1)>>1;//总方案数
    	REP(i,1,n)
    	{
    		answer-=1ll*(i-Max(arr[i].l,arr[i].left))*(Min(arr[i].r,arr[i].right)-i);//需要同时满足两个限制,所以直接对区间的端点取距离 i 近的那个就行了
    	}
    	Writeln(answer);
    	return 0;
    }
    
  • 相关阅读:
    JavaScript操作符instanceof揭秘
    Linux打开txt文件乱码的解决方法
    Working copy locked run svn cleanup not work
    poj 2299 UltraQuickSort 归并排序求解逆序对
    poj 2312 Battle City 优先队列+bfs 或 记忆化广搜
    poj2352 stars 树状数组
    poj 2286 The Rotation Game 迭代加深
    hdu 1800 Flying to the Mars
    poj 3038 Children of the Candy Corn bfs dfs
    hdu 1983 Kaitou Kid The Phantom Thief (2) DFS + BFS
  • 原文地址:https://www.cnblogs.com/Sxy_Limit/p/13775438.html
Copyright © 2011-2022 走看看