1. 程式人生 > 其它 >P5278 算術天才⑨與等差數列 題解

P5278 算術天才⑨與等差數列 題解

一道不錯的題目,只不過能被 hash 和維護若干次方和通過,本篇講正解。

考慮一個亂序序列重排後是等差數列的一些條件(設區間 \([l,r]\),公差為 \(d\)):

  1. 數列最大值 - 數列最小值 = \((r-l)*d\)
  2. 相鄰兩數的差的絕對值的最大公約數是 \(d\)
  3. 序列中沒有重複的數。

可以證明,這三個條件和亂序序列重排成等差數列是充要條件(我不會證)。

考慮線段樹維護一下,維護最大值,最小值,左端點值,右端點值,差的 gcd,PreMax。

其中 \(\text{PreMax}_i\) 表示最大的 \(x<i\) 滿足 \(a_i=a_x\),如果沒有就是 0。

這樣這三個條件就都很好判了,至於 \(\text{PreMax}\)

的維護考慮對值域離散化後連結串列 + set 維護一下就好了,離散化我用 map 因為懶。

CodeBase:CodeBase of Plozia

Code:

/*
========= Plozia =========
	Author:Plozia
	Problem:P5278 算術天才 9 與等差數列
	Date:2022/2/25
========= Plozia =========
*/

#include <bits/stdc++.h>
using std::map;
using std::set;
int gcd(int a, int b) { return (b == 0) ? a : gcd(b, a % b); }
int Abs(int x) { return (x > 0) ? x : (-x); }
int Max(int fir, int sec) { return (fir > sec) ? fir : sec; }
int Min(int fir, int sec) { return (fir < sec) ? fir : sec; }

typedef long long LL;
const int MAXN = 6e5 + 5;
int n, m, a[MAXN], Pre[MAXN], Aft[MAXN], cnt;
map <int, int> book;
set <int> s[MAXN];
struct node
{
	int l, r, Gcd, Maxn, Minn, PreNum, AftNum, PreMax;
	#define l(p) tree[p].l
	#define r(p) tree[p].r
	#define Gcd(p) tree[p].Gcd
	#define Maxn(p) tree[p].Maxn
	#define Minn(p) tree[p].Minn
	#define PreNum(p) tree[p].PreNum
	#define AftNum(p) tree[p].AftNum
	#define PreMax(p) tree[p].PreMax
	node operator +(const node &fir)
	{
		node c; c.l = l, c.r = fir.r, c.PreMax = Max(PreMax, fir.PreMax);
		c.Gcd = gcd(gcd(Gcd, fir.Gcd), Abs(fir.PreNum - AftNum));
		c.Maxn = Max(Maxn, fir.Maxn); c.Minn = Min(Minn, fir.Minn);
		c.AftNum = fir.AftNum; c.PreNum = PreNum; return c;
	}
}tree[MAXN << 2];

int Read()
{
	int sum = 0, fh = 1; char ch = getchar();
	for (; ch < '0' || ch > '9'; ch = getchar()) fh -= (ch == '-') << 1;
	for (; ch >= '0' && ch <= '9'; ch = getchar()) sum = sum * 10 + (ch ^ 48);
	return sum * fh;
}

void Build(int p, int l, int r)
{
	l(p) = l, r(p) = r;
	if (l == r) { Gcd(p) = 0, Maxn(p) = Minn(p) = PreNum(p) = AftNum(p) = a[l], PreMax(p) = Pre[l]; return ; }
	int mid = (l + r) >> 1; Build(p << 1, l, mid); Build(p << 1 | 1, mid + 1, r);
	tree[p] = tree[p << 1] + tree[p << 1 | 1];
}

void Change(int p, int x, node val)
{
	if (x == 0) return ;
	if (l(p) == r(p)) { tree[p] = val; return ; }
	int mid = (l(p) + r(p)) >> 1;
	if (x <= mid) Change(p << 1, x, val);
	else Change(p << 1 | 1, x, val);
	tree[p] = tree[p << 1] + tree[p << 1 | 1];
}

node Ask(int p, int l, int r)
{
	if (l(p) >= l && r(p) <= r) return tree[p];
	int mid = (l(p) + r(p)) >> 1;
	if (l <= mid && r > mid) return Ask(p << 1, l, r) + Ask(p << 1 | 1, l, r);
	else if (l <= mid) return Ask(p << 1, l, r);
	else return Ask(p << 1 | 1, l, r);
}

void Work1(int lastans)
{
	int x = Read() ^ lastans, y = Read() ^ lastans;
	Aft[Pre[x]] = Aft[x]; Pre[Aft[x]] = Pre[x];
	Change(1, Aft[x], (node){Aft[x], Aft[x], 0, a[Aft[x]], a[Aft[x]], a[Aft[x]], a[Aft[x]], Pre[Aft[x]]});
	s[book[a[x]]].erase(x); a[x] = y; Pre[x] = Aft[x] = 0;
	if (book.find(y) == book.end())
	{
		book[y] = ++cnt; s[cnt].insert(x);
		Change(1, x, (node){x, x, 0, y, y, y, y, 0});
		return ;
	}
	y = book[y];
	auto it = s[y].lower_bound(x);
	if (it == s[y].begin())
	{
		Aft[x] = *s[y].begin(); Pre[*s[y].begin()] = x;
		Change(1, x, (node){x, x, 0, a[x], a[x], a[x], a[x], 0});
		int tmp = *s[y].begin();
		Change(1, tmp, (node){tmp, tmp, 0, a[tmp], a[tmp], a[tmp], a[tmp], Pre[tmp]});
		s[y].insert(x);
	}
	else if (it == s[y].end())
	{
		--it;
		Pre[x] = *it; Aft[*it] = x;
		Change(1, x, (node){x, x, 0, a[x], a[x], a[x], a[x], Pre[x]});
		s[y].insert(x);
	}
	else
	{
		auto it2 = it; --it;
		Pre[x] = *it; Aft[x] = *it2;
		Aft[*it] = x; Pre[*it2] = x;
		Change(1, x, (node){x, x, 0, a[x], a[x], a[x], a[x], Pre[x]});
		int tmp = *it2;
		Change(1, tmp, (node){tmp, tmp, 0, a[tmp], a[tmp], a[tmp], a[tmp], Pre[tmp]});
		s[y].insert(x);
	}
}

void Work2(int &lastans)
{
	int l = Read() ^ lastans, r = Read() ^ lastans, k = Read() ^ lastans;
	if (l > r) std::swap(l, r); node tmp = Ask(1, l, r);
	if (((tmp.Maxn - tmp.Minn) == 1ll * (r - l) * k) && (tmp.Gcd == k || !tmp.Gcd) && (tmp.PreMax < l || k == 0)) puts("Yes"), ++lastans;
	else puts("No");
}

int main()
{
	n = Read(), m = Read(); int lastans = 0;
	for (int i = 1; i <= n; ++i)
	{
		a[i] = Read();
		if (book.find(a[i]) == book.end())
		{
			book[a[i]] = ++cnt; s[book[a[i]]].insert(i);
		}
		else
		{
			Pre[i] = *--s[book[a[i]]].end();
			Aft[*--s[book[a[i]]].end()] = i;
			s[book[a[i]]].insert(i);
		}
	}
	Build(1, 1, n);
	for (int _ = 1; _ <= m; ++_)
	{
		int opt = Read();
		if (opt == 1) Work1(lastans);
		else Work2(lastans);
	}
	return 0;
}