首页 > 其他分享 >[ABC282Ex] Min + Sum 题解

[ABC282Ex] Min + Sum 题解

时间:2024-02-29 11:59:41浏览次数:39  
标签:le Min int 题解 Sum min mid sum op

[ABC282Ex] Min + Sum 题解

题面传送门

题目要求有多少对 \((l, r)\) 满足 \(1 \le l \le r \le n\) 且 \(\sum_{i=l}^{r}{b_i} + \min_{i=l}^{r}{a_i} \le S\)。

考虑 CDQ 分治,那么我们需要不断寻找有多少对 \((l,r)\) 满足 \(L \le l \le M < r \le R\) 且 \(\sum_{i=l}^{r}{b_i} + \min_{i=l}^{r}{a_i} \le S\)。因为第一条限制,所以第二条限制可以转化为 \(\sum_{i=M+1}^{r}{b_i} + \sum_{i=l}^{M}{b_i} + \min(\min_{i=l}^{M}{a_i}, \min_{i=M+1}^{r}{a_i}) \le S\)。

这显然需要先进行前后缀和。我们无法做到枚举 \(l\) 又枚举 \(r\)。所以考虑枚举 \(r\)。容易发现 \(\min_{i=x}^{M}{a_i} \le \min_{i=x + 1}^{M}{a_i}\),于是我们双指针,找到一个 \(x\),对于当前枚举到的 \(r\) 满足 \(\min_{i=x}^{M}{a_i} < \min_{i=M+1}^{r}{a_i} \le \min_{i=x + 1}^{M}{a_i}\)。

那么现在,\([L,x]\) 中的点 \(l\) 需要满足 \(\min_{i=l}^{M}{a_i} + \sum_{i=l}^{M}{b_i} + \sum_{i=M+1}^{r}{b_i} \le S\)。

\((x,M]\) 中的点 \(l\) 需要满足 \(\sum_{i=l}^{M}{b_i} + \min_{i=M+1}^{r}{a_i} + \sum_{i=M+1}^{r}{b_i} \le S\)。

由于我们已知右端点 \(r\),所以可以分类讨论左端点 \(l\) 的情况。对不等式移项,求出其限制,最后发现这是一个插入删除后,求多少个插入后保留数满足小于某个数,这显然可以用 01 - trie 来解决。

最后时间复杂度 \(O(n \log n \log S)\)。

AC Code

#include <bits/stdc++.h>

using namespace std;
using LL = long long;

const int MAXN = 2e5 + 3;

int n;
LL S, ans = 0, a[MAXN], b[MAXN]; 
LL smi[MAXN], ssum[MAXN];

int top[2] = {1, 1}, eg[2][MAXN * 50][2], cnt[2][MAXN * 50];

inline void Insert(int op, LL x){ // 01 - trie 插入 
  int p = 1;
  for(int i = 49; i >= 0; i--){ int col = (x >> i) & 1;
    if(!eg[op][p][col]) eg[op][p][col] = ++top[op];
    p = eg[op][p][col], cnt[op][p]++;
  }
}
inline void Erase(int op, LL x){ // 01 - trie 删除 
  int p = 1;
  for(int i = 49; i >= 0; i--){ int col = (x >> i) & 1;
    p = eg[op][p][col], cnt[op][p]--;
  }
}
inline int query(int op, LL x){ // 01 - trie 求小于 x 的个数 
  if(x <= 0) return 0;
  int p = 1, ret = 0;
  for(int i = 49; i >= 0; i--){ int col = (x >> i) & 1;
    if(col == 1 && eg[op][p][0]) ret += cnt[op][eg[op][p][0]];
    if(!eg[op][p][col]) eg[op][p][col] = ++top[op];
    p = eg[op][p][col];
  }
  return ret;
}
void Clear(){ // 清空 01 - trie 
  for(int op = 0; op <= 1; op++){
    for(int i = 1; i <= top[op]; i++) cnt[op][i] = eg[op][i][0] = eg[op][i][1] = 0;
    top[op] = 1;
  }
}

void Solve(int l, int r){ // CDQ 分治 
  if(l == r){
    ans += (a[l] + b[l] <= S); // 统计 l = r 的区间 
    return;
  } 
  int mid = (l + r) >> 1;
  smi[mid] = a[mid], ssum[mid] = b[mid], Insert(0, ssum[mid] + smi[mid]); // 预处理 [l,mid] 区间 
  for(int i = mid - 1; i >= l; i--) smi[i] = min(smi[i + 1], a[i]), ssum[i] = ssum[i + 1] + b[i], Insert(0, ssum[i] + smi[i]);
  
  LL mi = 1e17, sum = 0;
  for(int i = mid + 1, j = mid + 1; i <= r; i++){ // 在 (mid,r] 中枚举答案右端点 
    mi = min(mi, a[i]), sum += b[i];
    while(j > l && smi[j - 1] >= mi) j--, Insert(1, ssum[j]), Erase(0, ssum[j] + smi[j]); // 01 - trie 处理 
    ans += query(1, S - sum - mi + 1) + query(0, S - sum + 1); // 通过 01 - trie 找到合法的在 [l,mid] 中的答案左端点,统计答案 
  }
  Clear(), Solve(l, mid), Solve(mid + 1, r); // 清空 01 - trie 后继续递归处理 
}

int main(){
  ios::sync_with_stdio(0), cin.tie(0);
  cin >> n >> S;
  for(int i = 1; i <= n; i++) cin >> a[i];
  for(int i = 1; i <= n; i++) cin >> b[i];
  Solve(1, n); 
  cout << ans;  
  return 0;
}

标签:le,Min,int,题解,Sum,min,mid,sum,op
From: https://www.cnblogs.com/huangqixuan/p/18043162

相关文章

  • P9836 种树 题解
    题目传送门前置知识质因数分解。贪心。题解思路先来解决一个问题,统计一个数\(x\)的正因数个数。可以将\(x\)质因数分解,得到每个数在\(x\)的质因数分解中出现了多少次。都知道质因数分解是每个数的唯一分解,那么统计个数的时候就只需要枚举每个质因数的出现个数。所以......
  • CF510C Fox And Names 题解
    CF510CFoxAndNames题解https://www.luogu.com.cn/problem/CF510C思路题意就是:确定一个小写字母的比较规则,使得给定的所有字符串在一开始就是按你确定的比较规则排序了的。可以发现:对于前后一对字符串,找到第一对不同的字符,是要这两个字符有合法的大小关系,就能满足题意。......
  • CF383C Propagating tree 题解
    题目链接:CF或者洛谷比较朴素的题,注意到这个涉及到子树变化,我们考虑优先处理出\(dfs\)序,方便处理。注意到第一个问题较为繁琐,我们着重解决下第一个问题。在树上问题,我们这种间隔点常常使用\(deep\)进行区分。根的\(deep\)为奇数,那么对自己子树范围内的奇数\(deep\)......
  • P2487 [SDOI2011] 拦截导弹 题解
    题目链接:拦截导弹约定:本题中提到的\(LDS\)和\(LIS\)不是严格单调,而是非严格单调,即为\(\le或者\ge\)。比较神奇的题,问的东西比较多,我们逐渐拆分:对于第一个问题而言,这个dp方程是很好写的:\[dp[i]=\max{dp[j]}+1(i<j,h[i]\leh[j],v[i]\lev[j])\]其中\(dp[i]\)即......
  • 题解 gym102900J 【Octasection】
    代码:#include<iostream>#include<algorithm>#include<stack>#include<vector>#include<cstdio>usingnamespacestd;typedefstructRectangle_tag{ intx1; intx2; inty1; inty2; Rectangle_tag(intx1_,intx2_,int......
  • 24冬网络流复习题解
    A是谁瞪了半个小时不会*2000呀,是谁呀是谁呀。感觉这题比部分紫题都难。。。首先发现选取字符的顺序并不重要,所以\(t\)可以看成\(26\)个字符要选的个数。设字符\(c\)出现了\(x\)次,那么直接向汇点连流量为\(x\)费用为\(0\)的边。然后考虑\(s_i\)与每个字符的关......
  • 2024年2月28号题解
    P4994终于结束的起点解题思路通过加法同余原理可以知道f[i]%m==0,那么f[i-1]%m=1,所有把f[i+1]%m=1转换成了f[i-1]%m=1的问题那么只需要填好斐波那契数列再判断就可以了,又因为斐波那契可能会超出int的范围那么我们对每一项斐波那契再取模就可以了代码......
  • 旅游景点 Tourist Attractions (壮压 DP)题解
    简化题意题目链接——不卡内存班题目链接——卡内存版给定\(n\)个点和\(m\)条边组成的无向图,按照一定限制要求停留\(2\simk+1\)共\(k\)个点(可以经过但不停留),求最短的从\(1\)出发到\(n\)的路径长。限制情况如下:共有\(q\)个限制,接下来\(q\)行,每行两个数\(x......
  • CF1408H Rainbow Triples 题解
    Description给定长度为\(n\)的序列\(p\)找出尽可能多的三元组\((a_i,b_i,c_i)\)满足:\(1\lea_i<b_i<c_i\len\)\(p_{a_i}=p_{c_i}=0\),\(p_{b_i}\ne0\)\(p_{b_i}\)互不相同。所有的\(a_i,b_i,c_i\)互不相同。输出最多可以选出多少个三元组,多组数据。\(\sumn\le......
  • P10160 [DTCPC 2024] Ultra 题解
    【题目描述】给你一个\(01\)序列,你可以进行如下操作若干次(或零次):将序列中形如\(101\cdots01\)的一个子串(即\(1(01)^k\),\(k\ge1\))替换成等长的\(010\cdots10\)(即\(0(10)^k\))。你要操作使得\(1\)的个数尽可能少,输出最少的\(1\)的个数。【思路】一开始看到这道题......