很多人会很自然的想到用two pointer来维护区间乘积, 但是从区间 [l,r] [ l , r ] 转移到 [l+1,r] [ l + 1 , r ] 的时候, 如果 a[l] a [ l ] 在模 p p 意义下的逆元不存在, 那么就无法转移
two stack:
用2个栈来维护区间中数的乘积
其中一个栈
S1
S
1
维护的是区间
[l,k](l≤k)
[
l
,
k
]
(
l
≤
k
)
的倒序乘积, 即栈底元素是
a[k]
a
[
k
]
, 上一层是
a[k]⋅a[k−1]
a
[
k
]
⋅
a
[
k
−
1
]
, ……,栈顶元素是:
a[k]⋅a[k−1]⋯a[l+1]⋅a[l]
a
[
k
]
⋅
a
[
k
−
1
]
⋯
a
[
l
+
1
]
⋅
a
[
l
]
, 当要删除
a[l]
a
[
l
]
这个数时, 直接pop掉栈顶元素
另外一个栈
S2
S
2
维护的是区间
[k+1,r](k<r)
[
k
+
1
,
r
]
(
k
<
r
)
的顺序乘积, 即栈底是
a[k+1]
a
[
k
+
1
]
, 上一层是
a[k+1]⋅a[k+2]
a
[
k
+
1
]
⋅
a
[
k
+
2
]
, ……,栈顶元素是
a[k+1]⋅a[k+2]⋯a[r−1]⋅a[r]
a
[
k
+
1
]
⋅
a
[
k
+
2
]
⋯
a
[
r
−
1
]
⋅
a
[
r
]
, 当要向右扩展
a[r+1]
a
[
r
+
1
]
这个数时, 直接push进
a[r+1]
a
[
r
+
1
]
与栈顶元素的乘积
这样会产生一个问题, 如果栈
S1
S
1
为空, 但是要删除
a[l]
a
[
l
]
这个数, 这个时候把栈
S2
S
2
所表示的区间的数倒序推进栈
S1
S
1
并维护好乘积, 同时清空栈
S2
S
2
, 并修改
S1
S
1
与
S2
S
2
所表示的区间, 再按照上面做就行了
举例:
区间
[1,3]
[
1
,
3
]
中有3个数字:
a,b,c
a
,
b
,
c
第一次查询
[1,2]
[
1
,
2
]
, 第二次查询区间
[2,3]
[
2
,
3
]
第一次查询时,
S1
S
1
为空,
S2
S
2
先右扩充2个数字, 其自底到顶的元素为:
a,a×b
a
,
a
×
b
所以第一次询问答案就是
S1
S
1
与
S2
S
2
栈顶的乘积:
a×b
a
×
b
这时要进行一次删除: 即删除区间
[2,2]
[
2
,
2
]
将
S2
S
2
所表示区间倒序更新到
S1
S
1
中, 并维护好乘积, 此时栈
S1
S
1
自底到顶是:
b,a×b
b
,
a
×
b
, 同时清空
S2
S
2
, 根据询问要求将
[2,2]
[
2
,
2
]
删除, 此时
S1
S
1
仅剩下一个元素
b
b
向右扩充一个位置
[3,3]
[
3
,
3
]
并维护好区间乘积, 此时栈
S2
S
2
中也只有一个元素
c
c
所以第二次询问答案就是与
S2
S
2
栈顶的乘积:
b×c
b
×
c
时间复杂度 O(n) O ( n ) 【与 q q <script type="math/tex" id="MathJax-Element-55">q</script>无关】
标程(未加读写外挂【会超时】):
#include<bits/stdc++.h>
#define fi first
#define sf scanf
#define se second
#define pf printf
#define pb push_back
#define mp make_pair
#define imax INT_MAX
#define imin INT_MIN
#define llmax LONG_LONG_MAX
#define llmin LONG_LONG_MIN
#define sz(x) ((int)(x).size())
#define mem(x,y) memset((x),(y),sizeof(x))
#define fup(i,x,y) for(int i=(x);i<=(y);i++)
#define fdn(i,x,y) for(int i=(x);i>=(y);i--)
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
using namespace std;
const int __=1e6+5;
int a[__],p;
struct node
{
ll val;int id;
node(ll x,int y):
val(x),id(y) {}
};
stack<node>S[3];
int main()
{
int n;sf("%d%d",&n,&p);
fup(i,1,n)sf("%d",&a[i]);
int q;sf("%d",&q);
S[1].push(node(1,0));
S[2].push(node(1,0));
int l=1,r=0;
while(q--)
{
int ql,qr;
sf("%d%d",&ql,&qr);
while(r<qr)
{
r++;
S[2].push(node(S[2].top().val*a[r]%p,r));
}
while(l<ql && sz(S[1])>1)
S[1].pop(),l++;
if(sz(S[1])==1 && l!=ql)
for(;sz(S[2])>1;S[2].pop())
{
int x=S[2].top().id;
S[1].push(node(S[1].top().val*a[x]%p,x));
}
while(l<ql && sz(S[1])>1)
S[1].pop(),l++;
pf("%lld\n",S[1].top().val*S[2].top().val%p);
}
return 0;
}