ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[hdu7020]Array

2021-08-03 21:02:19  阅读:176  来源: 互联网

标签:前缀 min sum tot 枚举 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\ne 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-l\le 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$​,显然当$tot\le \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\n",ans);
55     }
56     return 0;
57 }
View Code

 

标签:前缀,min,sum,tot,枚举,hdu7020,Array,复杂度
来源: https://www.cnblogs.com/PYWBKTDA/p/15096324.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有