首页 > 其他分享 >题解:CF1968G2 Division + LCP (hard version)

题解:CF1968G2 Division + LCP (hard version)

时间:2024-12-03 17:11:42浏览次数:10  
标签:Division le LCP int 题解 sqrt ans check mod

https://www.luogu.com.cn/problem/CF1968G2


CF1968G2 Division + LCP (hard version) 题解

前言

这题可以 \(O(n \sqrt{n} \log n)\) 再各种优化做,算法是二分、哈希(不知道包不包含根号分治,但是有用到根号分治的思想)。

如果读题解有些抽象的话可以看代码辅助理解。

题意转化

由于是从第一个位置开始分段,所以问题就是在字符串中,选出 \(k(l \le k \le r)\) 个不相交的且完全相同的子段,不过必须选择从头开始的一个子段,求最长长度。

思路

Easy Version

如果只用求对一个 \(k\) 求答案。

可以二分答案,然后在内部可以 \(O(n)\) 地 check 答案。

check 如何 \(O(n)\) 做呢?第一个位置开头的子段必须选择,贪心地,第一个位置选择的子段开始,从当前子段的结尾向后找到最近完全相等的子段,判断子段相等可以使用哈希。

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

Hard Version

想了很多种做法发现都不好做,猜一猜时间复杂度,假设时间复杂度带根号,没想到完全可做。

Hard Version 就是有多个 \(k\) 需要同时求解,我么不如直接求所有 \(1 \le k \le n\) 的答案。

  • 对于 \(1 \le k \le \sqrt{n}\) 的 \(k\),用 Easy Version 的做法求解,时间复杂度 \(O(n \sqrt{n} \log n)\)。
  • 对于 \(\sqrt{n} < k \le n\) 的 \(k\),则分段后最长的段最长 \(\sqrt{n}\),所以其答案必定小于等于 \(\sqrt{n}\)。
    • 枚举每个长度 \(l(1 \le l \le \sqrt{n})\),使用 Easy Version 中 check 的做法来求最多可以分几段,然后前缀和一下。
    • 时间复杂度 \(O(n \sqrt{n})\)。

两种做法合并起来即可。

优化1

发现两种情况处理的时间复杂度不同,一个 \(O(n \log n)\),另一个 \(O(n)\)。则我们可以平衡一下。

显然第一种做法给 \(1 \le k \le B\) 的直接求解,第二种做法就是长度小于等于 \(\frac{n}{B}\)。

这个 \(B\) 显然可以设为 \(200\)。

优化2

对于第一种做法,发现 \(k\) 从 \(1\) 到 \(B\) 对应的答案是不增的,所以二分答案时的上界可以由 \(ans_{k-1}\) 决定。

优化3

对于第一种做法,发现答案有很长一段连续,所以在二分前先 check \(ans_{k-1}\),若可以则 \(ans_k = ans_{k-1}\),否则再二分答案。

Code

#include <bits/stdc++.h>

using namespace std;
using LL = long long;
using Pair = pair<LL, LL>;

const int MAXN = 2e5 + 3;
const LL mod = 998244353;
const Pair B = {37, 47}; // 使用双哈希

int n, L, R, ans[MAXN];
char s[MAXN];
Pair Hash[MAXN], Bpow[MAXN];

Pair H(int l, int r){ // 求区间哈希值
  return {(Hash[r].first - Hash[l-1].first * Bpow[r-l+1].first % mod + mod) % mod,
           (Hash[r].second- Hash[l-1].second* Bpow[r-l+1].second% mod + mod) % mod};
}

bool check(int D, int k){ // 二分中的 check 函数
  int cnt = 0;
  for(int i = 1; i + D - 1 <= n; ){
    while(i + D - 1 <= n && H(i, i + D - 1) != H(1, D)) i++;
    cnt += i + D - 1 <= n && H(i, i + D - 1) == H(1, D), i = i + D;
    if(cnt >= k) return 1;
  }
  return 0;
}

void work(){
  cin >> n >> L >> R;
  for(int i = 1; i <= n; i++){
    cin >> s[i];
  }
  Bpow[0] = {1, 1};
  for(int i = 1; i <= n; i++){ // 预处理前缀哈希
    Bpow[i] = {Bpow[i-1].first * B.first % mod, Bpow[i-1].second* B.second% mod};
    Hash[i] = {(Hash[i-1].first * B.first % mod + s[i] - 'a' + 1) % mod,
               (Hash[i-1].second* B.second% mod + s[i] - 'a' + 1) % mod};
  }
  for(int i = 1; i <= n; i++) ans[i] = 0;
  for(int D = min(n, 1000); D >= 1; D--){ // 求解 200 < k <= n 的答案
    int mx = 0;
    for(int i = 1; i + D - 1 <= n; ){ // 类似 check 函数
      while(i + D - 1 <= n && H(i, i + D - 1) != H(1, D)) i++;
      mx += i + D - 1 <= n && H(i, i + D - 1) == H(1, D), i = i + D;
    }
    ans[mx] = max(ans[mx], D); // 前缀和
  }
  for(int i = n - 1; i >= 1; i--) ans[i] = max(ans[i], ans[i + 1]);
  ans[0] = n;
  for(int k = 1; k <= min(n, 200); k++){ // 求解 1 <= k <= 200 的答案
    int l = 0, r = ans[k - 1];
    if(check(r, k)) l = r;
    while(l < r){
      int mid = (l + r + 1) >> 1;
      if(check(mid, k)){
        l = mid;
      }else r = mid - 1;
    }
    ans[k] = max(ans[k], l);
  }
  for(int i = L; i <= R; i++) cout << ans[i] << " ";
  cout << "\n";
}

int main(){
  ios::sync_with_stdio(0), cin.tie(0);
  int T;
  cin >> T;
  while(T--) work();
  return 0;
}

标签:Division,le,LCP,int,题解,sqrt,ans,check,mod
From: https://www.cnblogs.com/huangqixuan/p/18584539

相关文章

  • 题解:P10217 [省选联考 2024] 季风
    P10217[省选联考2024]季风题解题目传送门。初步化简题目注:本篇题解的所有下标均从\(1\)开始。设\(sumx_h\)表示\(\sum_{i=1}^{h}{x_i}\),\(sumy_i\)表示\(\sum_{i=1}^{h}{y_i}\)。于是题目给出的三个公式可以转化为:\((\sum_{i=1}^{m}{x_{i}^{′}})+sumx_{[(m-1......
  • 题解:AT_abc282_h [ABC282Ex] Min + Sum
    [ABC282Ex]Min+Sum题解题面传送门。题目要求有多少对\((l,r)\)满足\(1\lel\ler\len\)且\(\sum_{i=l}^{r}{b_i}+\min_{i=l}^{r}{a_i}\leS\)。考虑CDQ分治,那么我们需要不断寻找有多少对\((l,r)\)满足\(L\lel\leM<r\leR\)且\(\sum_{i=l}^{r}{b......
  • 【Mysql 数据库 undo log 文件无限膨胀,性能下降问题解决方案】
    数据库undolog文件无限膨胀,性能下降问题解决方案1.问题描述在Mysql数据目录中发现有个undo文件非常大,并且持续增长并且Historylistlength非常大------------TRANSACTIONS------------Trxidcounter3569860310Purgedonefortrx'sn:o<3185146100......
  • CentOS7 yum 安装 提示 网络问题解决办法
    1.sudovi/etc/yum.repos.d/CentOS-Base.repo2.将里边文件替换(insert%d  清除所有内容)  [base]name=CentOS-$releasever-Base-Aliyunbaseurl=http://mirrors.aliyun.com/centos/$releasever/os/$basearch/gpgcheck=1gpgkey=http://mirrors.aliyun.com/centos/RP......
  • 牛客周赛 Round 70题解
    牛客周赛Round70题解A小苯晨跑#include<bits/stdc++.h>usingnamespacestd;voidsolve(){inta[4];for(inti=0;i<4;i++)cin>>a[i];sort(a,a+4);if(a[0]==a[3]){cout<<"NO\n";}els......
  • 宇视网络摄像机IPC通过国标28181协议,无法接入国产系统部署的视频接入汇聚平台的问题解
    目录一.客户问题具体描述二.问题解决过程2.1网络排查2.2检查摄像机本身设置三.问题排查结果3.1平台查看设备是否在线3.2设置相关观看权限3.2.1新增并设置相关资源组3.2.2设置需要观看视频的角色3.2.3设置客户端登录用户3.3最终观看结果四.补充知识4.1ping的相关知......
  • 题解:P11217 【MX-S4-T1】「yyOI R2」youyou 的垃圾桶
    链接https://www.luogu.com.cn/problem/P11217分析先不考虑维护垃圾桶的攻击力,假设我们已经知道了所有垃圾桶的攻击力。翻倍操作可以用左移(<<)实现。首先先计算出所有垃圾桶的伤害值,然后看看能抗几个整轮。然后考虑不能抗的情况。由于所有垃圾桶的攻击力都为正数,所以可以二......
  • centos7软件仓库停用问题解决
    首先这只是一种临时解决方案,centos7已经停止维护了,软件仓库2024年7月已经停了,不建议使用了,建议切换到rockyos9,rockyos9里面包管理工具是dnf,dnf目前是兼容yum命令的,升级rockos除了软件数据的迁移,使用习惯几乎完全一样。解决方案如下:#打开仓库文件目录cd/etc/yum.repos.d#......
  • P1746 离开中山路 JAVA题解 (广搜和双向广搜优化)
    题目背景《爱与愁的故事第三弹·shopping》最终章。题目描述爱与愁大神买完东西后,打算坐车离开中山路。现在爱与愁大神在 x1,y1x1​,y1​ 处,车站在 x2,y2x2​,y2​ 处。现在给出一个 n×n(n≤1000)n×n(n≤1000) 的地图,00 表示马路,11 表示店铺(不能从店铺穿过),爱与愁......
  • 题解:AT_abc382_d [ABC382D] Keep Distance
    题目传送门思路老样子,先看数据范围。\(2\leqN\leq12\)\(10N-9\leqM\leq10N\)加上限时五秒钟,所以可以放心的写。设\(X\)为输出的倒数第\(Y\)个数,\(Z\)为上一个数的值。观察样例,确定\(X\)的取值范围是\((Z+10)\sim(M-Y\times10+10)\)这样我们就可......