首页 > 其他分享 >[CF407E] k-d-sequence

[CF407E] k-d-sequence

时间:2023-07-10 15:24:07浏览次数:41  
标签:lc sequence int max min tr CF407E rc

[CF407E] k-d-sequence

复健不会写代码。

首先找充要条件,如一个子串 \(a_l,a_{l+1}...a_r\) 合法,则首先这些数互不重复,其次这些数对 \(d\) 取模相同,最重要的是

\[\dfrac{\max{a} - \min{a}}{d} - (r - l) \le k \]

左边表示最终形成的等差数列中的数的个数,\(r - l\) 表示已经存在的数,那么剩下的数就需要填充。

感觉不难维护,那么考虑扫描线 + 线段树的套路。先从大到小枚举左端点,考虑右端点满足何性质。把上式中和 \(r\) 有关的分离出来,等价于

\[\dfrac{\max{a} - \min{a}}{d} - r \le k - l \]

这启发我们在线段树上维护左边的这坨东西,下面称之为答案。\(-r\) 这一部分可以直接在建树的时候体现出来,注意到 \(\max a - \min a\) 必然是 \(d\) 的倍数,那么分式部分就可以转化为 \(\lfloor \frac{\max a}{d} \rfloor - \lfloor \frac{\min a}{d} \rfloor\)。考虑分开做 \(\max\) 和 \(\min\),发现这俩杂糅在一起很难处理答案,那么继续拆拆拆,分别再维护不算 \(\max\) 和不算 \(\min\) 的答案,每次就只用考虑一者的贡献了。

现在还需要做区间取 \(\max\) 的操作,注意到优良性质:线段树中的 \(\max\) 单调递增。所以可以直接二分,但是我的做法是线段树上二分,常数可能会大一些。因为我们上面维护了那么多东西所以可以不用考虑 \(\min\) 的影响,直接打乱重来即可。

时间复杂度是优秀的 \(O(n \log n)\),空间是 \(O(n)\)。常数比我的代码还大。

要注意,这题值域可以取到负数,因此需要整体平移。

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

namespace IO {
#define isdigit(x) (x >= '0' && x <= '9')
template<typename T>
inline void read(T &x) {
  x = 0; char ch = getchar(); int f = 0;
  for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
  for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
  if(f) x = -x;
}
template<typename T, typename... Rest>
inline void read(T &x, Rest&... rest) {
  read(x), read(rest...);
}
template<typename T>
inline void write(T x) {
  if(x < 0) putchar('-'), x = -x;
  if(x > 9) write(x / 10);
  putchar(x % 10 + '0');
}
#undef isdigit
}
using namespace IO;

constexpr int N = 2e5 + 10;
const LL inf = 9223372036854775807;
int n, k;
LL a[N], d;

map<LL, int> vis;

struct SegmentTree {
#define lc (k << 1)
#define rc (k << 1 | 1)
#define mid ((l + r) / 2)
  struct node {
    LL mx1, mx2, mn1, mn2;
    LL valx, valn, val;
    LL tagx, tagn;
  }tr[N << 2];

  void update(int k) {
    const node &l = tr[lc], &r = tr[rc];
    tr[k] = (node){max(l.mx1, r.mx1), min(l.mx2, r.mx2), max(l.mn1, r.mx1), min(l.mn2, r.mn2), 
                   min(l.valx, r.valx), min(l.valn, r.valn), min(l.val, r.val), -inf, inf};
  }

  void pushdown(int k, int l, int r) {
    if(tr[k].tagx > -inf) {
      const LL v = tr[k].tagx; tr[k].tagx = -inf;
      tr[lc].val = v / d + tr[lc].valn, tr[rc].val = v / d + tr[rc].valn;
      tr[lc].valx = v / d - mid, tr[rc].valx = v / d - r;
      tr[lc].mx1 = tr[lc].mx2 = tr[rc].mx1 = tr[rc].mx2 = v;
      tr[lc].tagx = max(tr[lc].tagx, v), tr[rc].tagx = max(tr[rc].tagx, v);
    }
    if(tr[k].tagn < inf) {
      const LL v = tr[k].tagn; tr[k].tagn = inf;
      tr[lc].val = -v / d + tr[lc].valx, tr[rc].val = -v / d + tr[rc].valx;
      tr[lc].valn = -v / d - mid, tr[rc].valn = -v / d - r;
      tr[lc].mn1 = tr[lc].mn2 = tr[rc].mn1 = tr[rc].mn2 = v;
      tr[lc].tagn = min(tr[lc].tagn, v), tr[rc].tagn = min(tr[rc].tagn, v);
    }
  }

  void build(int k, int l, int r) {
    if(l == r) {
      tr[k] = (node){a[l], a[l], a[l], a[l], a[l] / d - l, -a[l] / d - l, -l, -inf, inf};
      return ;
    }
    build(lc, l, mid), build(rc, mid + 1, r);
    update(k);
  }

  void modifyx(int k, int l, int r, int L, int R, LL v) {
    if(r < L || R < l || tr[k].mx2 >= v)
      return ;
    if(L <= l && r <= R && tr[k].mx1 <= v) {
      tr[k].mx1 = tr[k].mx2 = v, tr[k].val = v / d + tr[k].valn;
      tr[k].valx = v / d - r, tr[k].tagx = max(tr[k].tagx, v); 
      return ;
    }
    pushdown(k, l, r);
    modifyx(lc, l, mid, L, R, v);
    modifyx(rc, mid + 1, r, L, R, v);
    update(k); 
  }
  
  void modifyn(int k, int l, int r, int L, int R, LL v) {
    if(r < L || R < l || tr[k].mn1 <= v)
      return ;
    if(L <= l && r <= R && tr[k].mn2 >= v) {
      tr[k].mn1 = tr[k].mn2 = v, tr[k].val = -v / d + tr[k].valx;
      tr[k].valn = -v / d - r, tr[k].tagn = min(tr[k].tagn, v); 
      return ;
    }
    pushdown(k, l, r);
    modifyn(lc, l, mid, L, R, v);
    modifyn(rc, mid + 1, r, L, R, v);
    update(k); 
  }

  int query(int k, int l, int r, int L, int R, LL v) {
    if(r < L || R < l || tr[k].val > v)
      return 0;
    if(l == r) return l;
    pushdown(k, l, r);
    int res = query(rc, mid + 1, r, L, R, v);
    if(res) return res;
    return query(lc, l, mid, L, R, v);
  }
#undef lc
#undef rc  
#undef mid
}s;

int main() {
  read(n, k, d);
  for(int i = 1; i <= n; ++i)
    read(a[i]), a[i] += 1e9;
  if(d == 0) {
    int ansl = 1, ansr = 0;
    for(int i = 1, l = 1; i <= n; ++i) {
      if(a[i] != a[i - 1]) l = i;
      if(i - l > ansr - ansl)
        ansr = i, ansl = l;
    }
    printf("%d %d\n",ansl,ansr);
    return 0;
  }
  int ansl = 1, ansr = 0;
  s.build(1, 1, n);
  for(int l = n, cur = n; l >= 1; --l) {
    if(l < n && a[l] % d != a[l + 1] % d)
      cur = l, vis.clear();
    if(vis[a[l]]) {
      for(int j = vis[a[l]] + 1; j <= cur; ++j)
        vis[a[j]] = 0;
      cur = vis[a[l]] - 1;
    }
    vis[a[l]] = l;
    s.modifyx(1, 1, n, l + 1, cur, a[l]);
    s.modifyn(1, 1, n, l + 1, cur, a[l]);
    int r = s.query(1, 1, n, l, cur, k - l);
    if(r - l >= ansr - ansl) 
      ansr = r, ansl = l;
  }
  printf("%d %d\n",ansl,ansr);
}

标签:lc,sequence,int,max,min,tr,CF407E,rc
From: https://www.cnblogs.com/DCH233/p/17541226.html

相关文章

  • 首次使用Charles,Structure和Sequence中没有内容,Recording中有内容的解决方法
    1.首次使用Charles记录下载打开软件后,SSLProxying已经配置好了,但是Structure和Sequence中没有内容,而Recording中有内容解决办法:RecordingSettings中Exclude中Remove就可以了点击Proxy,点击RecordingSettings需要查看的内容可以在Include中添加......
  • 【CF1621G】Weighted Increasing Subsequences 题解(优化树状数组)
    CF传送门|LG传送门。优化树状数组+反向处理。Solution发现直接做不好下手。难点主要在求出所有的上升子序列并计算它们分别的贡献。所以需要反向考虑每个单点在什么情况下产生贡献。一个单点会产生多少贡献。一个单点产生贡献的条件很容易得到。一个是在一个上升子序......
  • saveOrUpdate failed with new sequence number
    Domainobject:<hibernate-mapping><classname="Trade"table="Trades"><idname="seqNum"column="SEQ_NUM"type="long"><generatorclass="sequence"><par......
  • YetAnotherRGBSequence
    [ABC266G]YetAnotherRGBSequence为了方便将\(r,g,b\)替换为\(a,b,c\)。考虑可以将\(a-=k,b-=k\),就变为\(a-k\)个\(a\),\(b-k\)个\(b\),\(c\)个\(c\),\(k\)个\(ab\),(这里我们已经将\(a,b\)减去\(k\),下文的\(a,b\)均指代减去后的结果)然后求排列总数,使得不构成新......
  • CF1144G Two Merged Sequences
    CF1144GTwoMergedSequences题意现在给你一个长度为\(n\)的序列你要把它拆成一个严格递增序列和一个严格递减序列如果不可行输出\(NO\)如果可行输出\(YES\)并输出每个数属于递增序列还是递减序列题解感觉脑子瓦特了,感觉这个\(dp\)的状态设计是比较自然的。首先我们考......
  • Scoring Subsequences
    ScoringSubsequencestimelimitpertest2.5secondsmemorylimitpertest256megabytesinputstandardinputoutputstandardoutputThe score ofasequence [s1,s2,…,sd][1,2,…,] isdefinedas s1⋅s2⋅…⋅sdd!1⋅2⋅…⋅!,where d!=1⋅2⋅…⋅d!=1......
  • Prioritized Sequence Experience Replay
    发表时间:2020文章要点:这篇文章提出了PrioritizedSequenceExperienceReplay(PSER),一个新的经验回放机制来提升训练速度和效果。主要的出发点就是不仅要给重要的transition高的priority,对于到达这个重要的transition的之前的那些transitions,也要增加它们的priority(alsoincre......
  • 「解题报告」CF1621G Weighted Increasing Subsequences
    比较套路的拆贡献题。考虑直接枚举那个\(j\),求有多少包含\(j\)的上升子序列满足这个子序列最后一个数的后面有大于\(a_j\)的数。首先对于\(j\)前面的选择方案是没有影响的,可以直接拿树状数组DP一遍得到。后面的过程我们可以找到从后往前第一个大于\(a_j\)的数的位置......
  • [ABC216G] 01Sequence 题解
    01Sequence题目大意构造一个满足\(m\)个形如\((l,r,x)\)的限制条件的\(01\)序列,其中\((l,r,x)\)表示区间\([l,r]\)的和不小于\(x\),你需要保证序列中\(1\)的个数最小。思路分析贪心的想,如果我们将限制按右端点排序,那么当遍历到一个区间,发现现有的和不满足限制条件......
  • CF1770F Koxia and Sequence
    一步都没想到,一定是状态不好吧,一定吧一定吧?加训数数!题意给定\(n,x,y\),定义好的序列\(\{a_i\}_{i=1}^n\)满足\(\sum\limits_{i=1}^na_i=x,\operatorname{OR}\limits_{i=1}^na_i=y\)。求所有好的序列的异或和的异或和。数据范围:\(1\len\le2^40,0\lex<......