首页 > 其他分享 >题解 For Problem. 完全参差序列

题解 For Problem. 完全参差序列

时间:2022-10-20 12:12:25浏览次数:82  
标签:last Log 题解 ll 预处理 序列 Problem 参差

Problem. 完全参差序列

题目背景

2022年,南京师范大学迎来了 120周年校庆 ,值此120周年校庆筹备工作全面启动之际,学校诚邀海内外校友、社会贤达、各界人士壬寅中秋相聚金陵,共赴节日盛典,共商教育大计,共襄发展盛举。但是,小周学长觉得新生也是学校的重要组成,因此决定邀请大家参加校庆聚会;

然而,请来了新生,如何站位却难住了小周学长——新生的能力参差不齐,纯粹按照身高来排列又显得古板,因此小周学长想到了一种特殊的排列方式——【 分段式参差排法-完全参差序列(S-F)】:即一段连续的学生排列满足排列中的学生 综合水平值 (一个根据多方面评判的的数值) 互不相同

小周学长想知道区间 [L, R] 之间最长 S-F 序列的长度。

输入格式

第一行两个整数 N,M。N 表示连续 N 个学生,编号为 0 到 N−1,M 表示询问的次数;

第二行 N 个整数,第 i 个数表示该学生队列第 i 个学生的 综合水平值 ai;

接下来 M 行每行两个整数 L,R,表示 小周学长 询问的区间。

输出格式

输出 M 行,每行一个整数对应询问区间内的 S-F 序列的最长长度。

数据范围

对于 50% 的数据:

  • 1 ≤ N, M ≤ 1000,

  • 0 ≤ L ≤ R ≤ N − 1,

  • 0 ≤ ai ≤ 10^5.

对于 100% 的数据:

  • 1 ≤ N, M ≤ 2 × 10^5,

  • 0 ≤ L ≤ R ≤ N − 1,

  • 0 ≤ ai ≤ 10^6.

时间和空间限制

2s / 64MB

 

题解

Tips:

本题原型为《信息学奥赛一本通》题目“与众不同”,数据规模和空间限制与原题相同,不过原题时间限制为1s,考虑到vijos评测机对python等语言的不友好,经测试:算法相同的情况下python竟然比c++慢了近10倍。因此将时间放宽到2s后依然会卡到python等语言。这我在出题前确实没考虑到,向大家陪个罪。以下是对于本题的几种解法。

 

解法一:

<预处理 + 二分 + ST表>

分析题目,首先我们发现可以 O(n) 预处理出 以 i 为结尾的最长完全参差序列,记 pos[val]: 上一个值为 val 的位置。

起始位置递推公式 last_i=max(last_i−1, pos(A_i)+1)

然后我们可以研究 last[ ] 的性质, 对于一个完全参差序列 i∈序列 j 来说,序列 j不一定是完全参差序列;但对于一个非完全参差序列 i∈序列 j 来说,序列 j 一定不是完全参差序列。所以最长序列对应的开始位置一定是随 i 单调不减的。

于是在查询区间[QL, QR]中 二分查找 位置 p 使得 last[p-1]<QL, last[p]>=QL。对于[QL, L): L − QLA,对于[L, QR]: ST表 查询最大值。

时间复杂度 O(NlogN+MlogN)

 

 

解法二:

<双指针 + RMQ(ST) + 二分>

首先我们用v[i]为以下标i的元素为结尾的最长完全参差序列长度,la[i]是该序列的起始下标;然后我们可以巧妙地利用双指针把v[i]和la[i]求出来,代码如下:

  for(int i=1,j=1;i<=n;i++)
  {
      mp[a[i]]++;
      while(j<=i&&mp[a[i]]>1)
          mp[a[j++]]--;
      v[i]=i-j+1,la[i]=j;
  }

求出v和a以后,我们对于每一次询问二分,把从左到右第一个起始位置没有超出a的完全参差序列找出来,最后用RMQ查询[l,r]之间的最大值即可。

 

解法三:

<dp + RMQ(线段树) + 二分>

读到这里,我们不难发现其实本题也就两个步骤:第一步预处理,第二步RMQ查询。第一步预处理有两种方法,一种是双指针(滑动窗口),一种是dp的思想;至于第二步RMQ可以用线段树和ST表来做,不过重点是预处理的部分,因为预处理的处理方式有点难想。

对于预处理,我们可以用dp来计算以a[i]为结尾的最长“完全参差序列”的长度len[i],以及“完全参差序列”的开头的下标indx[i],实现方式附上代码:

 for (int i = 1; i <= n; ++i)
 {
     int x = a[i] + dif; // dif = 1e6, 用来处理负数
     indx[i] = max(indx[i - 1], last[x] + 1); // last数组记录的是x最近出现的下标
     len[i] = i - indx[i] + 1; // 计算len
     last[x] = i; // 更新x最近出现的下标
 }

然后完成代码就没什么问题了,对于区间最值我们可以用线段树来维护,当然用ST也可,最后二分即可完成。

 

 

ps - -

最后,为大家附上AC代码 - -

 

 #include<bits/stdc++.h>
 using namespace std;
 typedef long long ll;
 const ll N = 2e5 + 5;
 ​
 //预处理部分
 ll n, Q;
 map<ll, ll> mp;
 ll a[N], b[N], c[N];
 ​
 //RMQ算法(ST表)
 ll Log[N];
 ll mx[22][N];
 ​
 ll ask(ll l, ll r)
 {
     ll k = Log[r - l + 1];
     return max(mx[k][l], mx[k][r - (1 << k) + 1]);
 }
 ​
 int main()
 {
     ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
     cin >> n >> Q;
 ​
     Log[1] = 0;
     for (ll i = 2; i <= n; i++)
         Log[i] = Log[i >> 1] + 1;//预处理Log
 ​
     for (ll i = 1; i <= n; i++)
         cin >> a[i];
 ​
     //双指针
     for (ll i = 1, j = 1; i <= n; i++)
    {
         mp[a[i]]++;
         while (j <= i && mp[a[i]] > 1)
             mp[a[j++]]--;
         b[i] = i - j + 1;
         c[i] = j;
    }
 ​
     //ST表
     for (ll i = 1; i <= n; i++)
         mx[0][i] = b[i];
     ll cur = Log[n];
     for (ll k = 1; k <= cur; k++)
    {
         for (ll i = 1; i <= n - (1 << k) + 1; i++)
        {
             mx[k][i] = max(mx[k - 1][i], mx[k - 1][i + (1 << (k - 1))]);
        }
    }
 ​
     //处理询问
     while (Q--)
    {
         ll x, y;
         cin >> x >> y;
         x++; y++;//偏移区间方便操作
 ​
         //二分出第一个开始位置大于等于x的(假如有的话)
         ll l = x, r = y;
         while (l < r)
        {
             ll mid = (l + r) >> 1;
             if (c[mid] >= x)r = mid;
             else l = mid + 1;
        }
 ​
         //对应分类讨论
         if (c[l] < x)
             cout << y - x + 1 << endl;
         else
             cout << max((l - 1) - x + 1, ask(l, y)) << endl;
    }
     return 0;
 }
 

标签:last,Log,题解,ll,预处理,序列,Problem,参差
From: https://www.cnblogs.com/zms396/p/16809405.html

相关文章

  • CF1742E Scuza题解
    CF1742EScuza题意简述\(t\)组数据,对于每组数据:有\(n\)级台阶,每级台阶比上一级高\(a_i\)米。有\(q\)次询问,每次询问给出一个腿长\(k\),问在每次跨上的高度不大......
  • 题解 P2224 [HNOI2001]产品加工
    一道很有趣的dp题。这道题是以答案为下标来设定状态,在这种生产问题这个套路还是挺常见的,需要积累一下。我们令\(f_{i,j}\)为前\(i\)个任务\(A\)机器花了\(j\)时......
  • 2017 ACM Arabella Collegiate Programming Contest div2的题,部分题目写个题解
    F.MonkeyingAround 维护点在多少个线段上​​http://codeforces.com/gym/101350/problem/F​​题意:有m个笑话,每个笑话的区间是[L,R],笑话种类有1e5,一开始所有猴子都在......
  • bzoj 2301: [HAOI2011]Problem b mobius反演 RE
    ​​http://www.lydsy.com/JudgeOnline/problem.php?id=2301​​设f(i)为在区间[1,n]和区间[1,m]中,gcd(x,y)=i的个数。设F(i)为在区间[1,n]和区间[1,m]中,gcd(x,y)%......
  • mysql函数 字符长度限制_MySQL中使用group_concat()函数数据字符过长报错的问题解决方
    selectGROUP_CONCAT(uid)asuids,spread_uidfromeb_user_spreadwhereuid<>spread_uidGROUPBYspread_uid使用GROUP_CONCAT函数将字符串连接起来,数据量大的时候,会......
  • CF 1012C. Hills 题解
    题目传送门:Link。算法:DP。设计状态第一眼看着道题就感觉像是DP,再观察数据范围大概是\(O(n^2)\)的时间复杂度。因为要求多个\(k\)的答案,那么状态第一维显然是令多......
  • 洛谷 P3224 [HNOI2012]永无乡 题解
    查询第\(k\)小值想到权值线段树。合并操作想到线段树合并。维护连通性想到并查集。并查集合并方向应与线段树合并方向一致。查询时,先求出并查集的根再在线段树上询......
  • 力扣_剑指Offer_个人题解day05
    day05剑指Offer04.二维数组中的查找题目描述:在一个n*m的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个高效的......
  • 力扣_剑指Offer_个人题解day03
    day03剑指Offer05.替换空格题目描述:请实现一个函数,把字符串s中的每个空格替换成"%20"。示例1:输入:s="Wearehappy."输出:"We%20are%20happy."限制:0<=s的长度......
  • 力扣_剑指Offer_个人题解
    day02剑指Offer06.从尾到头打印链表题目描述:输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。示例1:输入:head=[1,3,2]输出:[2,3,1]限制:0<=链......