题目链接: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. L2-008 最长对称子串 (回文子串 / DP / Manacher算法)

    对给定的字符串,本题要求你输出最长对称子串的长度.例如,给定Is PAT&TAP symmetric?,最长对称子串为s PAT&TAP s,于是你应该输出11. 输入格式: 输入在一 ...

  2. 牛客 | 小G的约数引起的对于 整数分块 学习

    整除分块是个啥:要求\(∑_{i = 1}^n{n/i}\) 的值,这时候暴力需要O(n)的时间.由于这个区间是连续的,且'/'是向下取整,当i不能整除k时,n/i会等于最小的i(也就是区间最左边的值 ...

  3. 《3D编程模式》写书-第6次记录

    大家好,这段时间我完成了对初稿的第二轮修改,已经把稿子提交给编辑了 这里是所有的的写书记录: <3D编程模式>写书记录 本轮修改主要进行了下面的修改: 修改UML描述 增加依赖关系 角色之 ...

  4. 腾讯视频客户端 MP4 下载

    腾讯视频直接使用客户端下载视频,得到的是 QLV 文件,这种加密视频文件只能通过腾讯视频客户端播放.最新版的腾讯客户端下载的 QLV 文件,使用各种转码软件都不能正常转码.从服务器下载的 TS 文件一 ...

  5. Go 标准库 net

    本篇文章主要介绍 Go 标准库中的 net 包,通过一个小例子介绍常用的 net 包函数/方法 Listen,Accept 和 Dial 等. 1. net 简介 Go 官网对 net 包的定义如下: ...

  6. 浅谈 Docker 网络:单节点单容器

    1.Docker 网络模型 Docker 在 1.7 版本中将容器网络部分代码抽离出来作为 Docker 的网络库,叫 libnetwork.libnetwork 中使用 CNM(Container ...

  7. 07-逻辑仿真工具VCS-Post processing with VCD+ files

    逻辑仿真工具-VCS 编译完成不会产生波形,仿真完成之后,生成波形文件,通过dve产看波形 vcd是波形文件的格式,但是所占的内存比较大,后面出现了vpd(VCD+)波形文件 将一些系统函数嵌入到源代 ...

  8. [转帖]解Bug之路-记一次中间件导致的慢SQL排查过程

    https://zhuanlan.zhihu.com/p/242265937 解Bug之路-记一次中间件导致的慢SQL排查过程 前言 最近发现线上出现一个奇葩的问题,这问题让笔者定位了好长时间,期间排 ...

  9. [转帖]在KingbaseES数据库中批量创建数据库/表

    1. 问题 如何在KingbaseES中批量创建表和库? 2. 通过shell脚本文件实现 有时候我们在进行测试的时候需要进行批量的建库以及建表,这时我们可以使用shell脚本实现或者是SQL实现,s ...

  10. kafka学习之五_多个磁盘的性能验证

    kafka学习之五_多个磁盘的性能验证 背景 周末在家学习kafka 上午验证了grafana+kafka_exporter的监控 下午想着验证一把性能相关. kafka学习之三里面,有成套的脚本. ...