D 动态序列

题目
https://ac.nowcoder.com/acm/contest/13504/D

给出 n ( 1 ≤ n ≤ 100000 ) n(1\le n\le 100000) n(1n100000)个整数 a i ( 1 ≤ a i ≤ 1 0 9 ) a_i(1\le a_i\le 10^9) ai(1ai109)的序列,有 q ( 1 ≤ q ≤ 1 0 5 ) q(1\le q\le 10^5) q(1q105)个询问,设序列长度为 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 bb(1b109)
2   b : 序 列 中 所 有 数 增 加 整 数 b ( 1 ≤ b ≤ 1 0 9 ) 2\ b:序列中所有数增加整数b(1\le b\le 10^9) 2 bb(1b109)
3   b : 在 序 列 头 部 添 加 一 个 整 数 b ( 1 ≤ b ≤ 1 0 9 ) 3\ b:在序列头部添加一个整数b(1\le b \le 10^9) 3 bb(1b109)
4   b : 在 序 列 尾 部 添 加 一 个 整 数 b ( 1 ≤ b ≤ 1 0 9 ) 4\ b:在序列尾部添加一个整数b(1\le b\le10^9) 4 bb(1b109)
5   p : 输 出 序 列 的 第 p ( 1 ≤ p ≤ l e n ) 个 数 , 并 将 结 果 对 1 0 9 + 7 取 模 5\ p:输出序列的第p(1 \le p \le len)个数,并将结果对10^9+7取模 5 pp1plen109+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 mulai+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 (mulai+add)bmulbai+addb,所以 m u l ∗ = b , a d d ∗ = b mul *= b,add *= b mul=badd=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) mulai+add+bmulai+(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 mulx+add=b,用这个 x x x来代替 b b b,加入序列里面。改变方程形式: x = ( b − a d d ) ∗ m u l − 1 x = (b - add) * mul ^{ -1} x=(badd)mul1,就可以转化为计算逆元的问题

在上述做法基础上,我们可以偏移序列在数组中的位置,维护头尾下标 ( l o w , h i g h (low,high (lowhigh),来实现操作 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;
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值