P4891 序列

P4891 序列

题目描述
给定两个长度为 n 的序列 A 和 B,定义序列 \(C_i=\max\limits_{j=1}^i A_j\)

定义当前的价值是 $\prod\limits_{i=1}^n \min(B_i,C_i) $。

现在有 q 次操作,每次操作将会修改序列 A 或者 B 中的一个位置,将会把数字变大。现在请求出每次修改之后的价值。

这题复杂度不准确


错误日志: while 用脱了。。, 以后用 while 判断当前一个就好


Solution

暴力修改
设修改区间为 \([l, r]\) , 每次修改乘以 \(a_{i}\), 除以 \(b_{i}\), 我们可以在 \(O(n)\) 的时间内处理出
\[\frac{\prod_{i = l}^{r}a_{i}}{\prod_{i = l}^{r}b_{i}}\]
上一次答案乘上这个就是这一次的答案
然后要求分母的逆元, \(10^{9} + 7\) 为质数, 用费马小定理
然后这样大概估一下复杂度上限是 \(O(n * (n + \log n))\)
所以数据貌似略水啊。。
当模拟练手了

Code

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<climits>
#define LL long long
#define REP(i, x, y) for(LL i = (x);i <= (y);i++)
using namespace std;
LL RD(){
    LL out = 0,flag = 1;char c = getchar();
    while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
    while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
    return flag * out;
    }
const LL maxn = 2000019, M = 1e9 + 7;
LL num, na;
LL b[maxn], c[maxn];
LL ans = 1;
LL get_inv(LL a){
    LL p = M - 2, ans = 1;
    while(p){
        if(p & 1)ans = ans * a % M;
        a = a * a % M;
        p >>= 1;
        }
    return ans % M;
    }
void init(){
    num = RD(), na = RD();
    REP(i, 1, num)c[i] = max(c[i - 1], RD());
    REP(i, 1, num)b[i] = RD();
    REP(i, 1, num)ans = ans * min(c[i], b[i]) % M;
    }
void solve(){
    while(na--){
        LL cmd = RD(), x = RD(), y = RD();
        LL frac = 1, son = 1;
        if(cmd == 0){
            while(c[x] < y){//把c[x]改为y
                if(c[x] < b[x]){
                    frac = frac * c[x] % M;
                    son = son * min(y, b[x]) % M;
                    }
                //else c'> c > b
                c[x] = y;
                x++;
                if(x > num)break;
                }
            }
        else{
            if(b[x] < c[x]){//b[x] --> y
                frac = frac * b[x] % M;
                son = son * min(c[x], y) % M;
                }
            //else b'> b > c
            b[x] = y;
            }
        ans = ((ans * son) % M + M) % M;
        ans = ((ans * get_inv(frac)) % M + M) % M;
        printf("%lld\n", ans % M);
        }
    }
int main(){
    init();
    solve();
    return 0;
    }

转载于:https://www.cnblogs.com/Tony-Double-Sky/p/9914022.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值