『分块』区间range

P r o b l e m \mathrm{Problem} Problem

『分块』区间range_第1张图片

S o l u t i o n \mathrm{Solution} Solution

使用分块的方式,将序列分时 k k k个一段,并维护每一段的前缀积和后缀积。

那么每一个长度为 k k k的区间就可以直接用 O ( 1 ) O(1) O(1)的方式来表示了。

本质是暴力美学。


C o d e \mathrm{Code} Code

#include 

using namespace std;

int n, k, P, A, B, C, D, m;
int a[21000000];
int res1[21000000];
int res2[21000000];
int L[10000000], R[10000000];

void work(void)
{
	for (int i=1;i<=n/k;++i) 
	{
		m ++;
		L[m] = R[m-1] + 1;
		R[m] = i * k;
	}
	if (R[m] < n) {
		m ++;
		L[m] = R[m-1] + 1;
		R[m] = n;
	}
	for (int i=1;i<=m;++i)
	{
		int res = 1;
		for (int j=L[i];j<=R[i];++j) {
			res = 1LL * res * a[j] % P;
			res1[j] = res; 
		}
		res = 1;
		for (int j=R[i];j>=L[i];--j) {
			res = 1LL * res * a[j] % P;
			res2[j] = res;
		}
	} 
	int res = 0;
	for (int i=1;i+k-1<=n;++i)
	{
		int j = i + k - 1;
		if (j % k == 0) res ^= res1[j];
		else res ^= 1LL * res2[i] * res1[j] % P;
	}
	cout << res << endl;
}

int main(void)
{
	freopen("range.in","r",stdin);
	freopen("range.out","w",stdout);
	cin >> n >> k >> P;
	cin >> A >> B >> C >> D;
	a[1] = A;
	for (int i=2;i<=n;++i)
		a[i] = 1LL*(1LL * B * a[i-1] + C) % D;
	work();
	return 0;
}

你可能感兴趣的:(『分块』区间range)