zoukankan      html  css  js  c++  java
  • 【做题记录】统计区间(哈希/扫描线)

    交题链接

    给你一个长度为 (n(nle 10^6)) 的序列,其中每个元素都在 ([1,n]) 范围中。

    询问有多少个区间满足区间中的元素都恰好出现 (2) 次。

    ( exttt{solution}~ exttt{1:}) 哈希

    我们考虑如果元素个数 (le 64) 时我们怎么做:

    给每个元素分配一个二进制位,记录到当前为止的异或和,同时用 map 记录同为这个异或和的位置数量(当然要保证出现位置在这个元素上上次出现以后),并累加答案。

    但是如果元素个数过多怎么办?答案是哈希!!!

    我们给每个元素随机附上一个值,向上面一样添加和求出答案。

    事实证明在随机赋值是正确率是非常高的。

    $ exttt{code}$
    #define Maxn 1000005
    typedef unsigned long long ll;
    int n,pos;
    ll ans;
    int a[Maxn],llast[Maxn],last[Maxn];
    ll ha[Maxn],pre[Maxn];
    unordered_map<ll,int> cnt;
    int main()
    {
    	 srand(time(0));
    	 n=rd();
    	 for(int i=1;i<=n;i++) a[i]=rd(),ha[i]=1llu*rand()*rand()*rand()*rand()*rand()*rand();
    	 cnt[0]++;
    	 for(int i=1;i<=n;i++)
    	 {
    	 	 while(pos<llast[a[i]]) cnt[pre[pos]]--,pos++;
    	 	 llast[a[i]]=last[a[i]],last[a[i]]=i;
    	 	 pre[i]=pre[i-1]^ha[a[i]];
    	 	 ans+=cnt[pre[i]];
    	 	 cnt[pre[i]]++;
    	 }
    	 printf("%llu
    ",ans);
    	 return 0;
    }
    

    ( exttt{solution}~ exttt{2:}) 扫描线

    我们记 (Pos(i,1/2/3)) 表示当前右端点以左,离数字 (i) 距离第 (1,2,3) 远的位置。

    易知当左端点位于 ([1,Pos(3)],[Pos(2)+1,Pos(1)]) 时答案不合法,所有不合法位置的并集就是所有不合法位置。

    可以通过总位置减去不合法位置来求出合法位置,因此变成了一道区间染色问题。

    我们通常用扫描线(不下传标记)来维护区间是否被染色,这题也可以这么维护。

    $ exttt{code}$
    #define Maxn 1000005
    typedef long long ll;
    int n,ans;
    int a[Maxn],Last[Maxn][3];
    struct TREE{ int laz,sum; }tree[Maxn<<3];
    inline void pushup(int p,int nl,int nr)
    {
    	 if(tree[p].laz>0) tree[p].sum=nr-nl+1;
    	 else tree[p].sum=tree[p<<1].sum+tree[p<<1|1].sum;
    }
    void add(int p,int nl,int nr,int l,int r,int k)
    {
    	 if(l>r) return;
    	 if(nl>=l && nr<=r) { tree[p].laz+=k,pushup(p,nl,nr); return; }
    	 int mid=(nl+nr)>>1;
    	 if(mid>=l) add(p<<1,nl,mid,l,r,k);
    	 if(mid<r) add(p<<1|1,mid+1,nr,l,r,k);
    	 pushup(p,nl,nr);
    }
    int main()
    {
    	 n=rd();
    	 for(int i=1;i<=n;i++) a[i]=rd();
    	 for(int i=1;i<=n;i++)
    	 {
    	 	 add(1,1,n,1,Last[a[i]][2],-1);
    		 add(1,1,n,Last[a[i]][1]+1,Last[a[i]][0],-1);
    		 Last[a[i]][2]=Last[a[i]][1];
    		 Last[a[i]][1]=Last[a[i]][0];
    		 Last[a[i]][0]=i;
    		 add(1,1,n,1,Last[a[i]][2],1);
    		 add(1,1,n,Last[a[i]][1]+1,Last[a[i]][0],1);
    		 ans+=i-tree[1].sum;
    	 }
    	 printf("%d
    ",ans);
    	 return 0;
    }
    
  • 相关阅读:
    CSharpGL(36)通用的非托管数组排序方法
    CSharpGL(35)用ViewPort实现类似3DMax那样的把一个场景渲染到4个视口
    CSharpGL(34)以从零编写一个KleinBottle渲染器为例学习如何使用CSharpGL
    CSharpGL(33)使用uniform块来优化对uniform变量的读写
    CSharpGL(32)矩阵与四元数与角度旋转轴的相互转换
    CSharpGL(31)[译]OpenGL渲染管道那些事
    CSharpGL(30)用条件渲染(Conditional Rendering)来提升OpenGL的渲染效率
    Go如何使用数据库、缓存
    Go内置常用包
    从零开始基于go-thrift创建一个RPC服务
  • 原文地址:https://www.cnblogs.com/EricQian/p/15500546.html
Copyright © 2011-2022 走看看