题目链接
Codeforces Round 974 (Div. 3) H题 Robin Hood Archery
思路1
因为警长是后手,按照最优的策略,只有每一种数的个数是偶数个的时候,警长会平局,否则警长会输。
随着询问区间端点的变化,答案的转移是 O ( 1 ) O(1) O(1)的。因此,我们可以使用基础莫队进行离线求解。
代码1
#pragma GCC optimize("O2")
#pragma GCC optimize("O3")
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define double long double
#define debug() cout<<"-------------------"<<endl;
typedef long long i64;
typedef pair<int, int> pii;
const int N = 2e5 + 5, M = 1e6 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f3f3f3f3f;
int n, m;
int a[N], ans[N];
int cnt[M];//桶
struct MOA
{
struct query
{
int id, l, r;
};
int len;
vector<query>q;
MOA() {}
MOA(int n, int m) {init(n, m);}
void init(int n, int m)
{
len = sqrt(n);
q.resize(m + 1);
}
void addquery(int i, int l, int r)
{
q[i] = {i, l, r};
}
int get(int x)
{ //求每个编号对应块
return x / len;
}
void add(int x, int &res)
{
if (cnt[x] % 2 == 0)
res++;
else res--;
cnt[x]++;
}
void del(int x, int &res)
{
if (cnt[x] & 1)
res--;
else res++;
cnt[x]--;
}
};
void solve()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
cnt[a[i]] = 0;
}
MOA moa(n, m);
for (int i = 1; i <= m; i++)
{
int l, r;
cin >> l >> r;
moa.addquery(i, l, r);
}
sort(moa.q.begin() + 1, moa.q.begin() + 1 + m, [&moa](MOA::query a, MOA::query b) {
int i = moa.get(a.l);
int j = moa.get(b.l);
if (i != j) return i < j;
return a.r < b.r;
});
int i = 0;//向r靠齐的指针
int j = 1;//向l靠齐的指针
int res = 0;
for (int k = 1; k <= m; k++)
{
int id = moa.q[k].id;
int l = moa.q[k].l;
int r = moa.q[k].r;
while (i < r)
{
moa.add(a[++i], res);
}
while (i > r)
{
moa.del(a[i--], res);
}
while (j < l)
{
moa.del(a[j++], res);
}
while (j > l)
{
moa.add(a[--j], res);
}
ans[id] = res;
}
for (int i = 1; i <= m; i++)
{
if (ans[i])
{
cout << "NO" << endl;
}
else cout << "YES" << endl;
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int test = 1;
cin >> test;
for (int i = 1; i <= test; i++)
{
solve();
}
return 0;
}
思路2
对于 [ a l , a r ] [a_{l},a_{r}] [al,ar]是否可以两两抵消,我们可以通过区间异或值是否为 0 0 0进行判断。
但这样随便一个hack都可以死(比如1,2,4,7)。
但我们可以进行随机赋值,把 [ 1 , 1 e 6 ] [1,1e6] [1,1e6]随机映射到一个极大的范围,之后使用异或哈希即可。
代码2
#pragma GCC optimize("O2")
#pragma GCC optimize("O3")
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define double long double
#define debug() cout<<"-------------------"<<endl;
typedef long long i64;
typedef unsigned long long u64;
typedef pair<int, int> pii;
const int N = 2e5 + 5, M = 1e6 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f3f3f3f3f;
std::mt19937 rnd(time(0));
int n, m;
int a[N];
u64 s[N], v[M];
void solve()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
s[i] = s[i - 1] ^ v[a[i]];
}
while (m--)
{
int l, r;
cin >> l >> r;
if ((r - l + 1) & 1)
{
cout << "NO" << endl;
}
else
{
if ((s[r] ^ s[l - 1]) == 0)
{
cout << "YES" << endl;
}
else cout << "NO" << endl;
}
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
for (int i = 1; i <= 1e6; i++)
{
v[i] = rnd();
}
int test = 1;
cin >> test;
for (int i = 1; i <= test; i++)
{
solve();
}
return 0;
}