题目大意
给出一个长度为
n
n
n的数组
b
1
,
b
2
,
⋯
,
b
n
b_1,b_2,\cdots,b_n
b1,b2,⋯,bn。
定义函数
f
(
l
,
r
)
=
∑
i
=
l
r
min
{
b
i
}
f(l,r)=\displaystyle\sum_{i=l}^r \min \{b_i\}
f(l,r)=i=l∑rmin{bi}
定义权值
A
i
=
∑
1
≤
l
≤
r
≤
i
f
(
l
,
r
)
A_i=\displaystyle\sum_{1\le l\le r\le i} f(l,r)
Ai=1≤l≤r≤i∑f(l,r)
A
i
A_i
Ai对
998244353
998244353
998244353取模。
求
A
1
⨁
A
2
⨁
⋯
⨁
A
n
A_1\bigoplus A_2\bigoplus\cdots\bigoplus A_n
A1⨁A2⨁⋯⨁An
时间限制
2s
数据范围
n ≤ 1 0 7 n\le 10^7 n≤107
题解
考虑如何求
f
f
f,如果弄个线段树或者别的,也十分不方便。
再来考虑如何求
A
i
A_i
Ai,不难发现
A
i
A_i
Ai只比
A
i
−
1
A_{i-1}
Ai−1多了以
i
i
i为右端点的区间的
f
f
f值。
发现了这一点,就非常好办了。
考虑如何快速求出
f
(
1
,
i
)
,
f
(
2
,
i
)
,
⋯
,
f
(
i
,
i
)
f(1,i),f(2,i),\cdots,f(i,i)
f(1,i),f(2,i),⋯,f(i,i)
根据性质,就可以发现这些值是递减的,因此可以用一个单调栈维护。
整体时间复杂度就是
O
(
n
)
O(n)
O(n)
Code
//#pragma GCC optimize (2)
//#pragma G++ optimize (2)
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <queue>
#include <map>
#define ll long long
#define G getchar
using namespace std;
ll read()
{
char ch;
for(ch = G();ch < '0' || ch > '9';ch = G());
ll n = 0;
for(;'0' <= ch && ch <= '9';ch = G())n = (n<<1)+(n<<3)+ch-48;
return n;
}
void write(ll x)
{
if (x > 9)
{
write(x / 10);
putchar(x % 10 + 48);
}
else putchar(x + 48);
}
const int N = 10000007;
const int mo = 998244353;
ll n , p , x , y , z , b , a;
ll ans , sum , s;
ll zz[N] , id[N] , top;
int main()
{
//freopen("i.in","r",stdin);
//freopen("e.out","w",stdout);
n = read();
p = read();
x = read();
y = read();
z = read();
b = read();
a = ans = b;
zz[1] = b;
id[1] = 1;
top = 1;
s = sum = b;
for (int i = 2 ; i <= n ; i++)
{
b = (a * x + b * y + z) % p;
for ( ; top && zz[top] > b ; top--)
{
sum = sum - zz[top] * (id[top] - id[top - 1]) % mo;
if (sum < 0) sum = sum + mo;
}
top++;
zz[top] = b;
id[top] = i;
sum = sum + b * (id[top] - id[top - 1]) % mo;
if (sum >= mo) sum = sum - mo;
s = s + sum;
if (s >= mo) s = s - mo;
a = s;
ans = ans ^ a;
//printf("%lld %lld\n", b , a);
}
printf("%lld\n", ans);
return 0;
}