zoukankan      html  css  js  c++  java
  • [hdu7020]Array

    (这是一个线性的做法)

    显然对于合法的区间,众数是唯一的,因此不妨枚举众数,将众数标记为1、其余数标记为-1,此时问题即求有多少个区间和大于0

    考虑暴力的做法:从左到右枚举右端点,记当前前缀和为$tot$​​,即查询之前有多少个前缀和小于$tot$​​​

    具体的,记$f_{i}$​​​为(当前)有多少个前缀和为$i$​​​​,即查询$sum_{i=min }^{tot-1}f_{i}$​​​,并将$f_{tot}$​​​加1​

    (其中$min$为历史前缀最小值,初始为$f_{0}=1$且$forall i e 0,f_{i}=0$)

    由于$tot$​​的变化是连续的,不难线性维护$sum_{i=min}^{tot-1}f_{i}$​​,时间复杂度为$o(n^{2})$​​

    进一步的,注意到1的个数和是$o(n)$​的,-1的段数和也是$o(n)$​的,因此将连续的一段-1一起处理

    具体的,考虑处理一段-1,假设这段-1之前的前缀和为$tot$​​​,这段-1的长度为$l$​​​,即查询$sum_{i=tot-l}^{tot-1}sum_{j=min}^{i-1}f_{j}$​​​,并将$forall tot-lle i<tot,f_{i}$​​​​加1

    对于修改,可以通过差分维护,并记差分数组为$Delta f_{i}$​​(定义$f_{i}=sum_{j=min}^{i}Delta f_{j}$​​​)

    对于查询,不妨暴力枚举$tot$,同样利用$tot$变化的连续性,线性维护$sum_{j=min}^{tot}Delta f_{j}$和$sum_{j=min}^{tot-1}f_{j}$​,那么不难得到查询的结果($tot$暴力枚举即代替了$i$),但时间复杂度仍为$o(n^{2})$

    考虑$min$​,显然当$totle min$时之后的部分必然都为0,不妨直接变为最终的$tot-l$​(注意更新$min$)

    考虑此时的复杂度,注意到每一次$mn$减少,都会减少对应$tot$的枚举,而最终$mn$至多为所有元素和,因此$tot$的枚举级别是1的个数,也即$o(n)$的

    对于单个1直接暴力"枚举"$tot$即可,显然是$o(n)$的

    最终,总复杂度为$o(n)$,可以通过

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 1000005
     4 #define ll long long
     5 stack<int>st;
     6 vector<int>v[N];
     7 int t,n,m,x,now,mn,cnt,s,f[N<<1];
     8 ll ans;
     9 void update(int l,int r){
    10     f[l]++,f[r+1]--;
    11     st.push(l),st.push(r+1); 
    12     cnt++;
    13 }
    14 void dec(int x){
    15     for(int i=0;i<x;i++){
    16         if (now==mn){
    17             now=mn=now-(x-i);
    18             cnt=s=0;
    19             return;
    20         }
    21         cnt-=f[now--],s-=cnt,ans+=s;
    22     }
    23 }
    24 int main(){
    25     scanf("%d",&t);
    26     while (t--){
    27         scanf("%d",&n);
    28         m=1e6,ans=0;
    29         for(int i=0;i<=m;i++)v[i].clear();
    30         for(int i=1;i<=n;i++){
    31             scanf("%d",&x);
    32             v[x].push_back(i);
    33         }
    34         for(int i=0;i<=m;i++){
    35             int lst=0;
    36             now=mn=n,cnt=s=0;
    37             update(now,now);
    38             //cnt=sum_{i=mn}^{tot}f_{i},s=sum_{i=mn}^{tot-1}sum_{j=mn}^{i}f_{j} 
    39             for(int j=0;j<v[i].size();j++){
    40                 if (lst+1<v[i][j]){
    41                     dec(v[i][j]-lst-1);
    42                     update(now,now+(v[i][j]-lst-1)-1);
    43                 }
    44                 s+=cnt,cnt+=f[++now],ans+=s;
    45                 update(now,now);
    46                 lst=v[i][j];
    47             }
    48             if (lst<n)dec(n-lst);
    49             while (!st.empty()){
    50                 f[st.top()]=0;
    51                 st.pop();
    52             }
    53         }
    54         printf("%lld
    ",ans);
    55     }
    56     return 0;
    57 }
    View Code
  • 相关阅读:
    RMAN动态视图
    无归档模式下的备份
    验证备份集-使用DBVERIFY工具
    手工备份控制文件和参数文件
    针对发起alter tablespace test begin backup 断电情况的处理
    Jenkins一次任务构建中如何处理多个git仓库
    Element-ui Tree组件实现单选
    前端覆盖式发布引发的使用体验提升
    客户端localStorage命名冲突问题
    git 查看和删除分支
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/15096324.html
Copyright © 2011-2022 走看看