如何卡满莫队
如何卡满莫队
应该是全网最先闲。
本文教会你如何卡满莫队,并不是莫队复杂度错了。
以下她它祂牠不分。
起因
起因是这样的,我的好同学 @emmoy 学习了莫队拼上分块 plus(和最重要的循环展开)艹掉古明地枣的袜子,由于她本人常数巨大,拿下了最劣解,8700+ms 险过。
突然我就很想欺负可爱的 emmoy,于是我决定 hack 她把她 T 飞。
过程
首先,她没有打快读,我们很自然的想到拉满
但那不重要,我们发现她打了分块 plus,拼上循环展开根本卡不掉,考虑对莫队下手。
我们观察她的排序比较函数:
bool cmp(const node &x,const node &y){
if(pos[x.l]^pos[y.l]) return x.l<y.l;
if(pos[x.l]&1) return x.r<y.r;
return x.r>y.r;
}
如此邪恶,竟然还加了奇偶化排序优化,根本无法下手,因此考虑对排序下手。
这个排序函数在
注意 sort 是不稳定排序,所以说
所以考虑如下数据(以她的块长
500000 12
1 490000
1 495000
1 490001
1 495001
1 490002
1 495002
700 490000
700 495000
700 490001
700 495001
700 490002
700 495002
我们排完序后发现是:
1 490000
700 490000
1 490001
700 490001
1 490002
700 490002
1 495000
700 495000
1 495001
700 495001
1 495002
700 495002
非常好,这样的话左指针就会移动
如你所见,傲娇的 emmoy 被我黑客了。
:::info[给出这道题的(针对 emmoy)的数据生成器]
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define int ll
const int N = 1e6 + 10;
const int INF = 1e18;
const int MOD = 998244353;
#define T0 1e6
#define Te 1e-5
#define DELTA 0.999
mt19937_64 rnd(chrono::steady_clock::now().time_since_epoch().count());
#define rand(l, r) uniform_int_distribution<int>(l, r)(rnd)
#define uniform() (double(rnd()) / rnd.max())
template <typename T>
void out(const T &t)
{
cout << t << '\n';
}
template <typename T, typename... Args>
void out(const T &t, const Args &...rest)
{
cout << t << ' ';
out(rest...);
}
signed main()
{
cin.tie(0)->sync_with_stdio(false), cout.setf(ios::fixed), cout.precision(10);
const int n = 5e5, m = 5e5;
out(n, m);
for (int i = 1; i <= n; ++i)
{
out(rand(1, n - 1), rand(-n, n));
}
const int cnt = 700;
int used = 0;
for (int i = 1; i <= cnt; ++i)
{
int l = (i - 1) * 700 + 1, r = i * 700;
for (int j = 1; j <= 175; ++j)
{
out(l, 490000 + j);
out(l, 495000 + j);
out(r, 490000 + j);
out(r, 495000 + j);
used += 4;
}
}
for (int i = used + 1; i <= m; ++i)
{
int l = rand(1, n), r = rand(1, n);
if (l > r)
{
swap(l, r);
}
out(l, r);
}
return 0;
}
:::
结果
这样多随几次数据就可以轻松把指针移动次数卡到
可惜的是 QOJ 的机子跑得飞快,每次指针移动跑
所以只卡掉了 emmoy。
如果你有更厉害的 hack 欢迎交流!!