2020牛客寒假算法基础集训营4 C-子段乘积(线段树)

题目:

在这里插入图片描述

分析:

题目中所要求的长度为k的连续子段的乘积对998244353取模余数的最大值,那么我们可以用线段树来存取区间的乘积,线段树的叶子节点存取对应下标的值,根节点存取左右子树的乘积,以此种方式建完树后,再遍历 [1,n-k+1] 每次取其中的最大值。

#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
using namespace std;

const int MAXN = 200005;
const long long mod = 998244353;
int n,k;
long long num[MAXN],ans;

struct Tree
{
    ll l,r,pro;
}tree[4*MAXN];

void Build(int l,int r,int i)
{
    tree[i].l = l;tree[i].r = r;
    if(l==r)
    {
        tree[i].pro = num[l];
        return;
    }
    int mid = (l + r) >> 1;
    Build(l,mid,2*i);
    Build(mid+1,r,2*i+1);
    tree[i].pro = ((tree[2*i].pro % mod) * (tree[2*i+1].pro % mod)) % mod;
}

ll Query(int i,int l,int r)
{
    if(tree[i].l>=l && tree[i].r<=r) return tree[i].pro % mod;
    int mid = (tree[i].l + tree[i].r) >> 1;
    ll tmpL=1,tmpR=1;
    if(tree[2*i].r >= l)
        tmpL = Query(2*i,l,r) % mod;
    if(tree[2*i+1].l <= r)
        tmpR = Query(2*i+1,l,r) % mod;
    return (tmpL * tmpR) % mod;
}

int main()
{
    ll tmp;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;++i)
        scanf("%lld",&num[i]);
    Build(1,n,1);
    for(int i=1;i+k-1<=n;++i)   
    {
        tmp = Query(1,i,i+k-1);   
        ans = max(ans,tmp);
    }
    printf("%lld\n",ans);
    return 0;
}

发布了33 篇原创文章 · 获赞 2 · 访问量 1708

猜你喜欢

转载自blog.csdn.net/weixin_42469716/article/details/104292960