省队集训Ⅱ-Day5

Day5

Gp

维护一个序列, 支持:

单点修改 (颜色和权值)

s 点往后, 选择一些连续的, 颜色不重复的点, 可以跳过 k 个点, 也可以直接结束选择, 求最大合法权值和.

考场上写了一个 nmlog2n 的做法, 建 O(n) 棵动态开点线段树, 每个颜色对应一棵, 维护两种信息: 区间内这个颜色的点数和区间内这个颜色的点的最大权值. 对于每个询问 (s,k), 容易得到, 选的颜色越多答案越优, 在 k 够用的情况下, 必须尽量往右走, 直到 k 用完后遇到一个已经遇到的颜色停下.

ks 一定时, 越往右走, 所需的 k 越多, 所以可以二分答案找选点的终点, 由于维护了每种颜色的区间出现数, 所以对于一个待定的终点 x, 在每棵线段树上查询区间 [s,x] 的出现数量, 只要出现超过 1 次, 超出部分就会消耗 k, 如果所有颜色需要的 k 足够, 则这个终点合法, 否则不合法, 单次 JudgeO(nlogn), 单次询问 O(nlog2n).

在询问终点的同时, 统计每种颜色在这个区间的最大权值, 然后求最大值之和, 这样最后的复杂度是 O(nmlog2n). 优化一下可以做到更小的常数, 但是都是 30, 接下来的代码是场外优化后的:

unsigned CntC(0), n, m, C[200005], V[200005], A, B, D, ColList[200005];
unsigned long long Ans(0);
char flg(0), Exist[200005];
set <unsigned> FindCol;
struct Node {
  Node *LS, *RS;
  unsigned Num, Max;
}N[10000005], *CntN(N), *List[200005];
void Udt(Node *x) {
  x->Max = x->Num = 0;
  if(x->LS) {
    x->Num += x->LS->Num;
    x->Max = max(x->Max, x->LS->Max);
  }
  if(x->RS) {
    x->Num += x->RS->Num;
    x->Max = max(x->Max, x->RS->Max);
  }
  return;
}
void Add (Node *x, unsigned Pos, unsigned L, unsigned R) {
  if(L == R) {
    x->Max = V[Pos];
    x->Num = 1;
    return;
  }
  unsigned Mid((L + R) >> 1);
  if(Pos <= Mid) {
    if(!(x->LS))  x->LS = ++CntN;
    Add(x->LS, Pos, L, Mid);
  } else {
    if(!(x->RS)) x->RS = ++CntN;
    Add(x->RS, Pos, Mid + 1, R);
  }
  return Udt(x);
}
void Era (Node *x, unsigned Pos, unsigned L, unsigned R) {
  if(L == R) {x->Max = 0, x->Num = 0; return;}
  unsigned Mid((L + R) >> 1);
  if(Pos <= Mid) {
    if(!(x->LS)) x->LS = ++CntN;
    Era(x->LS, Pos, L, Mid);
  } else {
    if(!(x->RS)) x->RS = ++CntN;
    Era(x->RS, Pos, Mid + 1, R);
  }
  return Udt(x);
}
unsigned Qry(Node *x, unsigned Low, unsigned High, unsigned L, unsigned R) {
  if(Low <= L && High >= R) return x->Num;
  unsigned Mid((L + R) >> 1), TmpNum(0);
  if(Low <= Mid) if(x->LS) TmpNum += Qry(x->LS, Low, High, L, Mid);
  if(High > Mid) if(x->RS) TmpNum += Qry(x->RS, Low, High, Mid + 1, R);
  return TmpNum;
}
unsigned Qry1(Node *x, unsigned Low, unsigned High, unsigned L, unsigned R) {
  if(Low <= L && High >= R) return x->Max;
  unsigned Mid((L + R) >> 1), TmpMax(0);
  if(Low <= Mid) if(x->LS) TmpMax = max(TmpMax, Qry1(x->LS, Low, High, L, Mid));
  if(High > Mid) if(x->RS) TmpMax = max(TmpMax, Qry1(x->RS, Low, High, Mid + 1, R));
  return TmpMax;
}
char Judge(unsigned L, unsigned R, unsigned Lim) {
  unsigned TmpNum(0);
  for (register unsigned i(1); i <= CntC; ++i) {
    TmpNum = Qry(List[ColList[i]], L, R, 1, n);
    Lim -= (TmpNum <= 1) ? 0 : (TmpNum - 1);
    if(Lim > 0x3f3f3f3f) return 0;
  }
  return 1;
}
int main() {
  n = RD(), m = RD();
  for (register unsigned i(1); i <= n; ++i) {
    C[i] = RD(), V[i] = RD();
    if(!List[C[i]]) List[C[i]] = ++CntN;
    Add(List[C[i]], i, 1, n);
    if(FindCol.find(C[i]) == FindCol.end()) {
      ColList[++CntC] = C[i];
      FindCol.insert(C[i]);
    }
  }
  C[n + 1] = C[n];
  for (register unsigned T(1); T <= m; ++T) {
    if(RD() & 1) {
      A = RD();
      Era(List[C[A]], A, 1, n);
      C[A] = RD(), V[A] = RD();
      if(!List[C[A]]) {
        List[C[A]] = ++CntN;
      }
      Add(List[C[A]], A, 1, n);
      if(FindCol.find(C[A]) == FindCol.end()) {
        ColList[++CntC] = C[A];
        FindCol.insert(C[A]);
      }
    } else {
      A = RD(), B = RD();
      Ans = 0;
      register unsigned Bot(min((A + B), n)), Top(n), Mid;
      while (Bot < Top) {
        Mid = (Bot + Top + 1) >> 1;
        if(Judge(A, Mid, B)) {
          Bot = Mid;
        } else {
          Top = Mid - 1;
        }
      }
      Ans = 0;
      for (register unsigned i(1); i <= CntC; ++i) {
        Ans += Qry1(List[ColList[i]], A, Bot, 1, n);
      }
      printf("%llu\n", Ans);
    }
  }
  return 0;
}

然后出场后被告知有一个极为无脑的 O(nm) 贪心, 为了优化, 用 set 存颜色数, 因为颜色数虽然是 O(n), 但实际一定远小于 n, 然后就 A 了, 可是为了卡 O(nm), 事后出了加强数据, 只能跑 55, 但是原数据在这种常数加持下是可以通过的 (甚至不需要 -o2, 真是见了鬼了):

unsigned CntC(0), n, m, C[200005], V[200005], A, B, D, ColList[200005], Max[200005];
unsigned long long Ans(0);
char flg(0);
set <unsigned> FindCol;
int main() {
  n = RD(), m = RD();
  for (register unsigned i(1); i <= n; ++i) {
    C[i] = RD(), V[i] = RD();
    if(FindCol.find(C[i]) == FindCol.end()) {
      ColList[++CntC] = C[i];
      FindCol.insert(C[i]);
    }
  }
  C[n + 1] = C[n];
  for (register unsigned T(1); T <= m; ++T) {
    if(RD() & 1) {
      A = RD();
      C[A] = RD(), V[A] = RD();
      if(FindCol.find(C[A]) == FindCol.end()) {
        ColList[++CntC] = C[A];
        FindCol.insert(C[A]);
      }
    } else {
      D = A = RD(), B = RD();
      Ans = 0;
      for (; A <= n; ++A) {
        if(Max[C[A]]) --B;
        if(B > 0x3f3f3f3f) break;
        Max[C[A]] = max(Max[C[A]], V[A]);
      }
      for (register unsigned i(D); i < A; ++i) {
        Ans += Max[C[i]];
        Max[C[i]] = 0;
      }
      printf("%llu\n", Ans);
    }
  }
  return 0;
}

然而所谓的正解 (指能过数据加强版) 确实可以 O(kmlogn), 思路 Prei 表示 i 前面第一个颜色为 Coli 的点的下标. 可以用 multiset 维护.

用数据结构维护 Val 的区间和, 可以使用树状数组.

然后用数据结构维护 [i,n]Pre 的最大值, 可知这个东西单调. 对于每个询问 (x,0), 先二分 [x,n] 的最大值, 得到一个 j, 使得 [j,n] 中的前缀最大值刚好大于等于 x, 次大值小于 x, 这个 j1 就是我们选的区间的右端点. 因为 jx 之后第一个和 [x,j1] 有同样颜色的点, 所以不能选, 前面的点都能选.

对于询问 (x,k), 枚举 k, 如果对于 k1 的区间右端点是 j, 那么二分查找满足 [j,n] 中前缀最大值刚好大于等于 jj, 使 j1 作为新的右端点, 以此类推, 所以算法有 k 倍常数.

过程中查询每一个区间的权值和作为答案, 需要 long long.

Of

这个题同样是手玩也不会, 建好 ACAM, 发现自己什么都不会了, 然后就浪费了 1.5h 的时间去推式子, 手玩样例, 做等比数列求和. 然后连代码都没敢交.

正解: 貌似也要建 ACAM, 但是这早就超出我能力范围了.

法二: 概率生成函数, 连 Trie 都不用建, 神奇的数学.

Lxl

这题就是沾了随机的光, 这个题可以用一个数组暴力过去, 得 30.

正解简直是人类智慧, 对于长度为 n 的二进制串, 用 n64unsigned long long 压位.

在最低位的整数不是 1 时, 不考虑前面的整数状态. 操作时, 仅对低位的数进行 3+1 的操作, 后面留 0, 直到最后一个数是 10000... 的形式, 这时, 记录总的后缀 0 数量进入答案, 删除最低位的整数, 假设一共进行了 x3+1 的操作, 则前面的每个数都 O(1)3x+(3x1+3x2+...+3+1).

以此类推, 最后的复杂度是 O((n64)2+nk), k 的意义是 64 长度的 01 串的操作数量.

LCM Sum

(i=1nlcm(i,i+1,i+2,...,i+k))%109+7

1n1018,0k30

考虑连续整数的 LCM 的值的性质, 可以知道对于同一个 k, i=xx+kilcm(x,x+1,...,x+k) 是个定值, O(k) 枚举所有小于 k 的质数即可求出定值 c. 求连乘之和, 然后乘这个定值的逆元. 连乘可以 O(n) 推出, 这样就能过 n107 的数据了. 用 CRT 优化可以做到 nk2, 具体操作我一个 CRT 都不会的人必然是不会的.

Random

n1018 以内的随机数 a1,a2,...,an, 1010 以内的 b1,b2,...,bn, 求一个 km 使得存在某种排序让 bi=(ai+k)%m 并且一一对应.

posted @   Wild_Donkey  阅读(56)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示