花神的嘲讽计划 莫队做法
前言
- loj
其实这题是主席树题单的但是没要求在线就用莫队屮一发- 张技问msjing这题有啥思路没,msjing给他胡了一个莫队+bitset的做法,然后撂了两天来做了
- 刷 Ynoi 大史的好处体现了
- \(Waring!\) 由于此题的提交处过少,不保证代码正确性
- msjing瞎搞导致内存爆炸了
solve
- 要求一个区间内序列有没有在原序列出现过,我们想到这与一个区间内一个元素是否在原序列出现过很相似,考虑向这个方向转化
- 我们发现要求这个区间内的序列必须完全相同,相当于字符串匹配,可以做个 \(KMP\) 的 \(O(n^2)\) 的暴力,将询问的序列变成字符串,并与原串做匹配
- 我们顺着这个向下想,由于询问定长,我们是不是可以对原串按 \(k\) 长拆分,这样很好比
- 可以的,复杂度大概是 \(O(n)\) 的,带一个巨大无比接近 \(\log\) 的常数
- 一个串和一个串显然不好做,我们将所有串做哈希映射,将所有串变成了哈希值,这样就好比了
- msjing是个兰丹不想写双哈希用的
unordered_map,可能会被卡 - 那问题变成了在一个区间里求一个数是否在一个序列出现过,这个就是莫队的基本操作了,出没出现过可以用 \(bool\) 数组维护,\(bitset\) 也行(实测好像 \(bitset\) 更慢但是空间更优?)
记录
- 数组

- \(bitset\)

- 但是你发现这个串有长度,所以我们将哈希值全放在右端点上(左端点好像也行)
点击查看代码
for (int i=1;i<=n-k+1;i++)
{
string s;
for (int j=i;j<=i+k-1;j++) s+=b[j]+'0';
if (!mp[s]) mp[s]=++tot;
// cerr << s << endl;
a[i+k-1]=mp[s];
}
- 但是你又发现可能在莫队时有不合法决策被加入,所以我们特殊处理一下左端点,这个看代码好理解
- 剩下的就是莫队基础操作了,时间复杂度 \(O(n \sqrt n)\)
点击查看代码
#include <bits/stdc++.h>
// #define int long long
using namespace std;
constexpr int maxn=2e5+10;
int read()
{
int x=0,f=1;
char ch=getchar();
while (ch<'0' || ch>'9')
{
if (ch == '-') f=-1;
ch=getchar();
}
while (ch>='0' && ch<='9')
{
x=(x<<1)+(x<<3)+ch-'0';
ch=getchar();
}
return x*f;
}
int n,m,k;
int a[maxn],b[maxn];
unordered_map<string,int> mp;
int tot;
int L[maxn],R[maxn],pos[maxn],cnt;
void init()
{
cnt=sqrt(n);
for (int i=1;i<=cnt;i++)
L[i]=R[i-1]+1,R[i]=cnt*i;
if (R[cnt]<n)
cnt++,L[cnt]=R[cnt-1]+1,R[cnt]=n;
for (int i=1;i<=cnt;i++)
for (int j=L[i];j<=R[i];j++)
pos[j]=i;
}
struct _
{
int l,r;
int strid;
int id;
}q[maxn];
int tt;
int col[maxn];
int bt[maxn];
void add(int x)
{
if (!col[x]) bt[x]=1;
col[x]++;
}
void del(int x)
{
col[x]--;
if (!col[x]) bt[x]=0;
}
int ans[maxn];
signed main()
{
n=read(),m=read(),k=read();
init();
// for (int i=1;i<=cnt;i++)
// cerr << L[i] << " " << R[i] << endl;
// for (int i=1;i<=n;i++)
// cerr << pos[i] << " ";
// cerr << endl;
for (int i=1;i<=n;i++) b[i]=read();
for (int i=1;i<=n-k+1;i++)
{
string s;
for (int j=i;j<=i+k-1;j++) s+=b[j]+'0';
if (!mp[s]) mp[s]=++tot;
// cerr << s << endl;
a[i+k-1]=mp[s];
}
// for (int i=1;i<=n;i++)
// cerr << a[i] << " ";
// cerr << endl;
for (int i=1;i<=m;i++)
{
int l=read(),r=read();
string g;
for (int j=1;j<=k;j++)
{
int x=read();
g+=x+'0';
}
if (!mp[g]) mp[g]=++tot;
// cerr << mp[g] << endl;
if (l+k-1>r)
{
ans[i]=1;
continue;
}
q[++tt]={l+k-1,r,mp[g],i};
/*特殊处理左端点*/
}
sort(q+1,q+1+tt,[](_ a,_ b)
{return pos[a.l] == pos[b.l] ? (a.l&1) == 1 ?
a.r<b.r : a.r>b.r : a.l<b.l;});
int l=1,r=0;
for (int i=1;i<=tt;i++)
{
// cerr << q[i].id << " : ";
// cerr << q[i].l << " " << q[i].r << endl;
while (l>q[i].l) add(a[--l]);
while (r<q[i].r) add(a[++r]);
while (l<q[i].l) del(a[l++]);
while (r>q[i].r) del(a[r--]);
// cerr << l << " " << r << endl;
// cerr << q[i].strid << endl;
// for (int i=1;i<=n;i++)
// cerr << bt[i] << " ";
// cerr << endl;
(!bt[q[i].strid]) ? ans[q[i].id]=1 : ans[q[i].id]=0;
}
for (int i=1;i<=m;i++)
ans[i] ? puts("Yes") : puts("No");
return 0;
}
$\mathscr{msjing}$

浙公网安备 33010602011771号