题目
https://ac.nowcoder.com/acm/contest/13504/D
给出
n
(
1
≤
n
≤
100000
)
n(1\le n\le 100000)
n(1≤n≤100000)个整数
a
i
(
1
≤
a
i
≤
1
0
9
)
a_i(1\le a_i\le 10^9)
ai(1≤ai≤109)的序列,有
q
(
1
≤
q
≤
1
0
5
)
q(1\le q\le 10^5)
q(1≤q≤105)个询问,设序列长度为
l
e
n
len
len,序号从
1
1
1开始,每个询问有如下操作:
1
b
:
序
列
中
所
有
数
乘
以
整
数
b
(
1
≤
b
≤
1
0
9
)
1\ b:序列中所有数乘以整数b(1\le b\le 10^9)
1 b:序列中所有数乘以整数b(1≤b≤109)
2
b
:
序
列
中
所
有
数
增
加
整
数
b
(
1
≤
b
≤
1
0
9
)
2\ b:序列中所有数增加整数b(1\le b\le 10^9)
2 b:序列中所有数增加整数b(1≤b≤109)
3
b
:
在
序
列
头
部
添
加
一
个
整
数
b
(
1
≤
b
≤
1
0
9
)
3\ b:在序列头部添加一个整数b(1\le b \le 10^9)
3 b:在序列头部添加一个整数b(1≤b≤109)
4
b
:
在
序
列
尾
部
添
加
一
个
整
数
b
(
1
≤
b
≤
1
0
9
)
4\ b:在序列尾部添加一个整数b(1\le b\le10^9)
4 b:在序列尾部添加一个整数b(1≤b≤109)
5
p
:
输
出
序
列
的
第
p
(
1
≤
p
≤
l
e
n
)
个
数
,
并
将
结
果
对
1
0
9
+
7
取
模
5\ p:输出序列的第p(1 \le p \le len)个数,并将结果对10^9+7取模
5 p:输出序列的第p(1≤p≤len)个数,并将结果对109+7取模
题目保证所有操作都是合法的!
思路
维护两个变量
m
u
l
mul
mul、
a
d
d
add
add,假设序列中原来的数为
a
i
a_i
ai,设最终结果为
m
u
l
∗
a
i
+
a
d
d
mul * a_i + add
mul∗ai+add,则可以:
- 进行操作 1 1 1时, ( m u l ∗ a i + a d d ) ∗ b ⇒ m u l ∗ b ∗ a i + a d d ∗ b (mul * a_i + add) * b\Rightarrow mul * b * a_i + add * b (mul∗ai+add)∗b⇒mul∗b∗ai+add∗b,所以 m u l ∗ = b , a d d ∗ = b mul *= b,add *= b mul∗=b,add∗=b
- 进行操作 2 2 2时, m u l ∗ a i + a d d + b ⇒ m u l ∗ a i + ( a d d + b ) mul * a_i + add + b \Rightarrow mul * a_i + (add + b) mul∗ai+add+b⇒mul∗ai+(add+b),所以 a d d + = b add += b add+=b
- 当添加一个数 b b b时,为了保持询问时计算结果的方法是统一的,则需要计算一个 x x x,使得: m u l ∗ x + a d d = b mul * x + add = b mul∗x+add=b,用这个 x x x来代替 b b b,加入序列里面。改变方程形式: x = ( b − a d d ) ∗ m u l − 1 x = (b - add) * mul ^{ -1} x=(b−add)∗mul−1,就可以转化为计算逆元的问题
在上述做法基础上,我们可以偏移序列在数组中的位置,维护头尾下标 ( l o w , h i g h (low,high (low,high),来实现操作 3 3 3和操作 4 4 4。进行操作 5 5 5的时候,数的真实下标就可以根据头下标和 p p p计算出来.
特别注意:数组要开足够大
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 3e5 + 7;
const int mod = 1000000007;
ll a[maxn],mul=1,add,s,x;
int n,q,l,r;
ll qpow(ll a,ll n) {
ll c=1;
while(n) {
if(n&1) c=a*c%mod;
n>>=1;
a=a*a%mod;
}
return c;
}
int main() {
scanf("%d%d",&n,&q);
for (int i=100001; i<=100000+n; ++i) {
scanf("%lld",&a[i]);
if(l==0) l=i;
r=i;
}
while(q--) {
scanf("%lld%lld",&s,&x);
if(s==1) {
mul = (mul*x)%mod;
add = (add*x)%mod;
}
else if(s==2) {
add=(add+x)%mod;
}
else if(s==3) {
a[--l]=(x-add+mod)%mod*qpow(mul,mod-2)%mod;
}
else if(s==4) {
a[++r]=(x-add+mod)%mod*qpow(mul,mod-2)%mod;
}
else {
printf("%lld\n",(mul*a[l+x-1]%mod+add)%mod);
}
}
return 0;
}