[2020牛客寒假第四场C题] 最大连续子段乘积 //线段树/乘法逆元

Problem

2020牛客寒假训练赛第四场C题-题目链接

题意:给定n(<=2e5)的序列和k,求长度为 k 的连续子段的乘积对 998244353 取模余数的最大值


Solutions

1.线段树

思路:线段树维护区间乘积,枚举起点查询[i,i+k-1]的乘积更新最大值

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<map>
#include<algorithm>
#include<queue>
#include<math.h>
#include<set>
#include<vector>
using namespace std;
#define Inf 0x7fffffff
typedef long long ll;
const int N=200007;
const ll p=998244353;
int n,o;
ll a[N],t[N*4],ans;
inline void push_up(int k){
	t[k]=(t[k<<1]*t[k<<1|1])%p;
}
void build(int l,int r,int k){
	if(l==r){
		t[k]=a[l];
		return;
	}
	int mid=(l+r)>>1;
	build(l,mid,k<<1);
	build(mid+1,r,k<<1|1);
	push_up(k);
}
ll query(int L,int R,int l,int r,int k){
	if(L<=l&&R>=r)return t[k];
	int mid=(l+r)>>1;
	ll re=1;
	if(L<=mid)re=(re*query(L,R,l,mid,k<<1))%p;
	if(R>mid)re=(re*query(L,R,mid+1,r,k<<1|1))%p;
	return re;
}
	
	
int main(){
	cin>>n>>o;
	for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
	build(1,n,1);
	for(int i=1;i<=n-o+1;i++){
		ll now=query(i,i+o-1,1,n,1);
		ans=max(ans,now);
	}
	cout<<ans;
}

2.乘法逆元

思路:尺取法+乘法逆元。因为模数p为质数,由费马小定理, ai*aip-2≡1 (mod p),所以ai于aip-2互为乘法逆元,这样就可以处理尺取法里的除法了。(注意处理ai为0的情况)
乘法逆元:a/b mod p = a*B mod p, 其中B是b关于模p的乘法逆元

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<map>
#include<algorithm>
#include<queue>
#include<math.h>
#include<set>
#include<vector>
using namespace std;
#define Inf 0x7fffffff
typedef long long ll;
const int N=200007;
const ll p=998244353;
int n,k;
ll a[N],ans;
ll qpow(ll x,ll e,ll mod){
	ll re=1;
	while(e){
		if(e&1){
			re=re*x%mod;
		}
		x=x*x%mod;
		e>>=1; 
	} 
	return re%mod;
}
int main(){
	cin>>n>>k;
	for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
	int l=1,r=0;
	ll now=1;
	while(++r<=n){
		while(r-l+1>k)now=(now*qpow(a[l++],p-2,p))%p;
		if(a[r]==0){
			now=1;
			l=r+1;
		}else{
			now=(now*a[r])%p;
			if(r-l+1==k)ans=max(ans,now);
		}
	}
	cout<<ans;
}

猜你喜欢

转载自blog.csdn.net/qq_45530271/article/details/104274007