题目链接: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. Codeforces Round #665 (Div. 2) A - D题题解

    成功拼手速提前过了AC两题,估计因为这个原因排名挺高的,B题晚上做的时候没绕出来,wa4发... 1401A - Distance and Axis 如果 \(n\) 小 于 \(k\) ,则必须将\ ...

  2. idea创建父子项目

    1. 首先创建大的project 父工程:  2. 点击下一步之后: 3. 点击下一步,填写项目存放地址,点击finish: 4. 完成之后删除不需要的文件,保留pom文件,检查对应的jar和spri ...

  3. windows 系统关闭占用端口的应用

    开发中有时候开发工具把程序关闭了,但是后台并没有真正关闭程序,导致再次启动相同端口的程序时报端口已经被使用的错误,这时如何强制关闭已占用的端口 1.打开dos对话框 2.查找被占用的端口的进程号 ne ...

  4. vue学习笔记 十二、通过计算属性获取定义的状态数据

    系列导航 vue学习笔记 一.环境搭建 vue学习笔记 二.环境搭建+项目创建 vue学习笔记 三.文件和目录结构 vue学习笔记 四.定义组件(组件基本结构) vue学习笔记 五.创建子组件实例 v ...

  5. vue-draggable 学习和使用

    vue-draggable 学习和使用 https://www.jianshu.com/p/e8ff1e1cafb1

  6. js判断undefined

    if (item2.shifoushiyong === 1) { if( typeof(item2.koufen) == "undefined" ) { item2.koufen ...

  7. 2023Java面试学习网站推荐

    本文给大家推荐博主收藏的6个程序员面试学习站点,按照项目简介.网站截图.是否收费供大家参考. 1. JavaGuide 网站地址:https://javaguide.cn 项目简介:「Java学习 + ...

  8. DC逻辑综合工具简介-Design Compiler

    逻辑综合简介 逻辑综合:代码转变为网表 FPGA:代码转变为FPGA内部的数字单元 在进行综合的时候往往会使用一些脚本工具 需要学会看综合之后的报告 1.目标 进行综合需要读入RTL设计,还需要用到f ...

  9. 永久激活Windows10专业版及其它版本【亲测有效2022-03-16,两种方式】

    前言 小编最近使用公司的电脑,开始出现让你激活的提示,而且每次开机都会弹出来,小编忍住了:但是过不了半个月开始给你在桌面上显示了,一直显示和水印一样.小编忍无可忍,必须找个办法给你消灭掉!!,于是小编 ...

  10. 【MCU】单片机如何检测市电通断?(应用甚广~)

    [来源]https://mp.weixin.qq.com/s/TQKtEbxS8WSo3D1MecdMIw