https://ac.nowcoder.com/acm/contest/3005/C
题目描述
给出一个长度为 n 的数列 ,求其长度为 k 的连续子段的乘积对 998244353 取模余数的最大值。
思路
这个题目可以尺取做,但是需要用逆元还要注意0的情况,不如线段树直接,线段树维护每一个区间的连乘积,最后进行多次查询取一个最大值,注意取模
#include <bits/stdc++.h>
#pragma warning (disable:6031)
#pragma warning (disable:4996)
#define mem(a, b) memset(a, b, sizeof a);
using namespace std;
const int N = 2e5 + 10;
const int mod = 998244353;
typedef long long ll;
struct p {
int l, r;
ll multi_sum;
ll max_sum;
ll lsum, rsum;
};
struct SegementTree {
p c[N * 4];
void build(int l, int r, int k) {
c[k].l = l;
c[k].r = r;
c[k].multi_sum = 0;
c[k].max_sum = 0;
if (l == r) {
cin >> c[k].multi_sum;
c[k].max_sum = c[k].multi_sum;
c[k].lsum = c[k].rsum = c[k].multi_sum;
return ;
}
int mid = (l + r) / 2;
build(l, mid, k << 1);
build(mid + 1, r, k << 1 | 1);
c[k].lsum = c[k << 1].lsum;
c[k].rsum = c[k << 1 | 1].rsum;
c[k].lsum %= mod;
c[k].rsum %= mod;
if (c[k << 1].lsum == c[k << 1].multi_sum)c[k].lsum = c[k].lsum * c[k << 1 | 1].lsum;
if (c[k << 1 | 1].rsum == c[k << 1 | 1].multi_sum)c[k].rsum = c[k].rsum * (c[k << 1].rsum);
c[k].lsum %= mod;
c[k].rsum %= mod;
c[k].multi_sum = c[k << 1].multi_sum * c[k << 1 | 1].multi_sum;
c[k].multi_sum %= mod;
c[k].max_sum = max(c[k << 1].max_sum, c[k << 1 | 1].max_sum);
c[k].max_sum = max(c[k].max_sum, (c[k << 1].rsum * c[k << 1 | 1].lsum) % mod);
}
ll query(int l, int r, int k) {
if (c[k].l >= l && c[k].r <= r) {
return c[k].multi_sum % mod;
}
int mid = c[k].l + c[k].r;
mid /= 2;
ll res = 1;
if (l <= mid) {
res *= query(l, r, k << 1);
res %= mod;
}
if (r > mid) {
res *= query(l, r, k << 1 | 1);
res %= mod;
}
return res % mod;
}
};
SegementTree st;
int main()
{
ios::sync_with_stdio(0);
int n, k;
cin >> n >> k;
st.build(1, n, 1);
ll ans = -1;
for (int i = 1; i + k - 1 <= n; i++) {
ans = max(ans, st.query(i, i + k - 1, 1));
}
printf("%lld\n", ans);
return 0;
}