题目链接:CF 或者 洛谷

挺有意思的题,一开始看到了 \(start+k\times step\),以为是根号分治方向的题,结果发现这题还给了一个“重排”操作玩玩。所以这题其实算是结论题。

  1. 首先我们明确一点,最小操作次数,一定不会低于区间种类 \(cnt\) 的。因为我们观察到每次操作至多会减少一个种类的数,但前提是这个种类的数在这个区间里的位置是等差数列。那么很显然,其实答案是具有上界的。

  2. 考虑重排操作,我们随便怎么都能操作,不如让相同颜色相邻就行,这样就能形成等差数列了,那么最简单的方式自然就是排序了,排序以后执行 \(cnt\) 次删除,每次删除一个连续颜色段。

  3. 考虑特殊情况,那就是第一次操作该怎么办?因为每次操作是删除以后才进行重排,而不是重排后删除,所以第一次有两种可能,第一种就是已经存在了至少一种数成等差,这种数我们删去后重排,答案依旧是数的种类。如果不存在呢,那么无论你咋选,都删不掉一个种类的数,随便选一种删掉,然后重排后就是答案 \(cnt\),这种显然要多加一个第一次的“无意义的删除”。

问题就转变为判断区间种类数与是否存在等差连续段。很显然,这个数据范围,我们可以考虑下莫队怎么做。种类很简单就不说了,基础莫队题。说说判断是否存在某种颜色的连续段,我们考虑为每一种颜色分组,来考虑对于一种颜色来说,单点加入和删除的影响:

  1. 单点加入,显然要么就是从左加入要么从高右加入,我们可以记录一个 \(diffStep\) 表示公差,不等于公差显然这个种类就无法选择,我们能选择的种类假如说为 \(diff\),那么就该 \(-1\),然后注意到,我们并不能重复删除,所以其实可以开一个布尔数组 \(vis\) 记录一下这种颜色是否被去掉贡献了,如果这种颜色已经不满足,显然就不需要再判断是否与上一个的下标之差为公差了。

  2. 单点删除,貌似不是很好做,因为你删除的时候,可能原来的等差数列已经出现了好几种公差了,而且公差出现的次数可能也不一定为 \(1\),所以这时候公差貌似应该用一个哈希表记录情况了?当公差只剩一种的时候,其实就该满足题意了。

但,又是需要数据结构降智的一天,删除既然这么多情况判断,干脆不做删除不就好了吗?还得维护哈希表之类的,带常数啥的,我们只加不减的回滚莫队就好了,直接不要删除操作就行来了,当你觉得某个操作麻烦时,就不要了,至此解决完原问题。只需要维护当前的种类数,和公差满足题意的种类数即可。

细节

用啥数据结构来维护序列呢,我们显然用双端队列就好了,往右加入,显然是 \(idx-back\) 是新公差,往左加入则是 \(front-idx\) 才是新公差。然后注意一下有哪些量发生变化,比如 \(vis\) 表示是否这个数不能作为贡献,\(diffStep\) 表示每一种颜色的最新的公差,\(val\) 表示加入到队头的数,因为回滚莫队回滚的是 \(l\),所以回滚队头就行了。暴力啥的一模一样的,没啥好说的。

参照代码
#include <bits/stdc++.h>

// #pragma GCC optimize("Ofast,unroll-loops")
// #pragma GCC optimize(2) // #define isPbdsFile #ifdef isPbdsFile #include <bits/extc++.h> #else #include <ext/pb_ds/priority_queue.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/trie_policy.hpp>
#include <ext/pb_ds/tag_and_trait.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/list_update_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/exception.hpp>
#include <ext/rope> #endif using namespace std;
using namespace __gnu_cxx;
using namespace __gnu_pbds;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef tuple<int, int, int> tii;
typedef tuple<ll, ll, ll> tll;
typedef unsigned int ui;
typedef unsigned long long ull;
typedef __int128 i128;
#define hash1 unordered_map
#define hash2 gp_hash_table
#define hash3 cc_hash_table
#define stdHeap std::priority_queue
#define pbdsHeap __gnu_pbds::priority_queue
#define sortArr(a, n) sort(a+1,a+n+1)
#define all(v) v.begin(),v.end()
#define yes cout<<"YES"
#define no cout<<"NO"
#define Spider ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
#define MyFile freopen("..\\input.txt", "r", stdin),freopen("..\\output.txt", "w", stdout);
#define forn(i, a, b) for(int i = a; i <= b; i++)
#define forv(i, a, b) for(int i=a;i>=b;i--)
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
#define endl '\n'
//用于Miller-Rabin
[[maybe_unused]] static int Prime_Number[13] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}; template <typename T>
int disc(T* a, int n)
{
return unique(a + 1, a + n + 1) - (a + 1);
} template <typename T>
T lowBit(T x)
{
return x & -x;
} template <typename T>
T Rand(T l, T r)
{
static mt19937 Rand(time(nullptr));
uniform_int_distribution<T> dis(l, r);
return dis(Rand);
} template <typename T1, typename T2>
T1 modt(T1 a, T2 b)
{
return (a % b + b) % b;
} template <typename T1, typename T2, typename T3>
T1 qPow(T1 a, T2 b, T3 c)
{
a %= c;
T1 ans = 1;
for (; b; b >>= 1, (a *= a) %= c)if (b & 1)(ans *= a) %= c;
return modt(ans, c);
} template <typename T>
void read(T& x)
{
x = 0;
T sign = 1;
char ch = getchar();
while (!isdigit(ch))
{
if (ch == '-')sign = -1;
ch = getchar();
}
while (isdigit(ch))
{
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
x *= sign;
} template <typename T, typename... U>
void read(T& x, U&... y)
{
read(x);
read(y...);
} template <typename T>
void write(T x)
{
if (typeid(x) == typeid(char))return;
if (x < 0)x = -x, putchar('-');
if (x > 9)write(x / 10);
putchar(x % 10 ^ 48);
} template <typename C, typename T, typename... U>
void write(C c, T x, U... y)
{
write(x), putchar(c);
write(c, y...);
} template <typename T11, typename T22, typename T33>
struct T3
{
T11 one;
T22 tow;
T33 three; bool operator<(const T3 other) const
{
if (one == other.one)
{
if (tow == other.tow)return three < other.three;
return tow < other.tow;
}
return one < other.one;
} T3() { one = tow = three = 0; } T3(T11 one, T22 tow, T33 three) : one(one), tow(tow), three(three)
{
}
}; template <typename T1, typename T2>
void uMax(T1& x, T2 y)
{
if (x < y)x = y;
} template <typename T1, typename T2>
void uMin(T1& x, T2 y)
{
if (x > y)x = y;
} constexpr int N = 1e5 + 10;
int pos[N]; struct Mo
{
int l, r, id; bool operator<(const Mo& other) const
{
return pos[l] ^ pos[other.l] ? l < other.l : r < other.r;
}
} node[N]; int cnt, tmpCnt; //种类数
int diff, tmpDiff; //满足题意等差数列的数量
deque<int> step[N], tmpStep[N]; //每种数维护个双端队列表示下标序列
int diffStep[N], tmpDiffStep[N]; //每种数的最新公差
bool vis[N], tmpVis[N]; //这种数是否已经算过了不能作为贡献
int a[N], ans[N];
//不需要回滚的右端点加入
inline void addR(const int idx)
{
const int val = a[idx];
if (step[val].empty())diff++, cnt++; //加入一个新的种类数
else
{
if (diffStep[val] and !vis[val] and idx - step[val].back() != diffStep[val]) //至少存在两个数才有公差不为0
{
vis[val] = true;
diff--;
}
diffStep[val] = idx - step[val].back();
}
step[val].push_back(idx);
} stack<int> backVis; //vis数组的回滚
stack<pii> backDiff; //diffStep数组的回滚
stack<int> backVal; //step数组的队头回滚
//需要回滚的左端点加入
inline void addL(const int idx)
{
const int val = a[idx];
if (step[val].empty())diff++, cnt++;
else
{
if (diffStep[val] and !vis[val] and step[val].front() - idx != diffStep[val])
{
vis[val] = true;
diff--;
backVis.push(val);
}
backDiff.emplace(val, diffStep[val]);
diffStep[val] = step[val].front() - idx;
}
step[val].push_front(idx);
backVal.push(val);
} int n, q; inline void solve()
{
cin >> n;
const int siz = sqrt(n);
forn(i, 1, n)cin >> a[i], pos[i] = (i - 1) / siz + 1;
cin >> q;
forn(i, 1, q)
{
auto& [l,r,id] = node[i];
cin >> l >> r, id = i;
}
sortArr(node, q);
int l = 1, r = 0, last = 0;
forn(i, 1, q)
{
auto [L,R,id] = node[i];
if (pos[L] == pos[R])
{
//暴力判断
forn(i, L, R)
{
if (tmpStep[a[i]].empty())tmpCnt++, tmpDiff++;
else
{
if (tmpDiffStep[a[i]] and !tmpVis[a[i]] and i - tmpStep[a[i]].back() != tmpDiffStep[a[i]])
{
tmpVis[a[i]] = true;
tmpDiff--;
}
tmpDiffStep[a[i]] = i - tmpStep[a[i]].back();
}
tmpStep[a[i]].push_back(i);
}
ans[id] = tmpCnt + (tmpDiff == 0);
forn(i, L, R)tmpDiffStep[a[i]] = 0, tmpStep[a[i]].clear(), tmpVis[a[i]] = false;
tmpCnt = tmpDiff = 0;
continue;
}
if (pos[L] != last)
{
forn(i, 1, n)vis[a[i]] = false, step[a[i]].clear(), diffStep[a[i]] = 0;
cnt = diff = 0;
r = min(pos[L] * siz, n);
l = r + 1;
last = pos[L];
}
while (r < R)addR(++r);
const int preCnt = cnt, preDiff = diff;
int tmpL = l;
while (tmpL > L)addL(--tmpL);
ans[id] = cnt + (diff == 0); //diff没有满足种类的就得+1
while (!backVis.empty())vis[backVis.top()] = false, backVis.pop();
while (!backDiff.empty())
{
auto [val,diffVal] = backDiff.top();
diffStep[val] = diffVal;
backDiff.pop();
}
while (!backVal.empty())step[backVal.top()].pop_front(), backVal.pop(); //只会回滚队头
cnt = preCnt, diff = preDiff;
}
forn(i, 1, q)cout << ans[i] << endl;
} signed int main()
{
// MyFile
Spider
//------------------------------------------------------
// clock_t start = clock();
int test = 1;
// read(test);
// cin >> test;
forn(i, 1, test)solve();
// while (cin >> n, n)solve();
// while (cin >> test)solve();
// clock_t end = clock();
// cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
}
\[时间复杂度为 \ O(q\sqrt{n})
\]

CF351D Jeff and Removing Periods 题解的更多相关文章

  1. CF&&CC百套计划3 Codeforces Round #204 (Div. 1) D. Jeff and Removing Periods

    http://codeforces.com/problemset/problem/351/D 题意: n个数的一个序列,m个操作 给出操作区间[l,r], 首先可以删除下标为等差数列且数值相等的一些数 ...

  2. Codeforces 351D Jeff and Removing Periods(莫队+区间等差数列更新)

    题目链接:http://codeforces.com/problemset/problem/351/D 题目大意:有n个数,每次可以删除掉数值相同并且所在位置成等差数列的数(只删2个数或者只删1个数应 ...

  3. Codeforces Round #204 (Div. 2)->B. Jeff and Periods

    B. Jeff and Periods time limit per test 1 second memory limit per test 256 megabytes input standard ...

  4. Codeforces 352B - Jeff and Periods

    352B - Jeff and Periods 思路:水题,考验实现(implementation)能力,来一波vector[允悲]. 代码: #include<bits/stdc++.h> ...

  5. B. Jeff and Periods(cf)

    B. Jeff and Periods time limit per test 1 second memory limit per test 256 megabytes input standard ...

  6. CF352B Jeff and Periods 模拟

    One day Jeff got hold of an integer sequence a1, a2, ..., an of length n. The boy immediately decide ...

  7. 『题解』Coderforces352A Jeff and Digits

    更好的阅读体验 Portal Portal1: Codeforces Portal2: Luogu Description Jeff's got n cards, each card contains ...

  8. codeforces B. Jeff and Periods 解题报告

    题目链接:http://codeforces.com/problemset/problem/352/B 题目意思:给出一个长度为n的序列   a1, a2, ..., an(序号i,1 <= i ...

  9. code forces Jeff and Periods

    /* * c.cpp * * Created on: 2013-10-7 * Author: wangzhu */ #include<cstdio> #include<iostrea ...

  10. cf B. Jeff and Periods

    http://codeforces.com/contest/352/problem/B #include <cstdio> #include <cstring> #includ ...

随机推荐

  1. HTML+CSS小实战案例 (照片墙特效、代码展示)

    预览图: HMTL代码部分 <!DOCTYPE html> <html lang="en"> <head> <meta charset=& ...

  2. freeswitch的任务引擎问题与解决方案

    概述 freeswitch核心框架中有一个定时任务系统task,在开发过程中用来做一些延时操作和异步操作很方便. 我们在VOIP的呼叫流程中,经常会有一些对实时性要求没那么高的操作,或者会有阻塞流程的 ...

  3. js - body的滚动事件的坑

    文章来源 : https://www.cnblogs.com/Zting00/p/7497629.html 踩过些坑,得到的结论,不一定精确 1. body的滚动条,刷新页面的时候不会回到顶部.其他d ...

  4. airsim+px4无人机仿真平台

    0. 架构图 1. 主机列表 对应的ip地址与选择的系统,根据实际情况进行修改 主机IP 组件 系统 192.168.0.28 mavporxy linux-centos7.6 192.168.0.2 ...

  5. [转帖]db file sequential read-数据文件顺序读取

    https://www.cnblogs.com/xibuhaohao/p/9959593.html 等待事件: "db file sequential read" Referenc ...

  6. [转帖]Active Session History (ASH)

    Introduction V$ACTIVE_SESSION_HISTORY DBA_HIST_ACTIVE_SESS_HISTORY Enterprise Manager Performance Pa ...

  7. [转帖]性能分析之TCP全连接队列占满问题分析及优化过程(转载)

    https://www.cnblogs.com/wx170119/p/12068005.html 前言 在对一个挡板系统进行测试时,遇到一个由于TCP全连接队列被占满而影响系统性能的问题,这里记录下如 ...

  8. 【转帖】【奇技淫巧】Linux | 统计网络-netstat

    theme: condensed-night-purple 小知识,大挑战!本文正在参与"程序员必备小知识"创作活动. 在构建生产服务器时,我们有的时候需要统计网络接口状况,比如T ...

  9. [转帖]总结:Tomcat的IO模型

    一.介绍 对于 linux 操作系统,IO 多路复用使用的是 epoll 方式,对于 windows 操作系统中 IO 多路复用使用的是 iocp 方式,对于 mac 操作系统 IO 多路复用使用的是 ...

  10. BPF的简单学习

    BPF的简单学习 前言 本来规划过年期间学习一下bpf相关的内容 但是因为自己没有坚持学习,所以到最后一天才开始整理. 本来想深入学习一下相关内容,但是已经感觉已经无法完成. 最近大半年进行了很多性能 ...