子段乘积(牛客)

刚开始以为就是一个前缀和加双指针,遍历一下就好了

刚开始的思路就搞一个S数组然后把输入进去的数组前i位相乘的到S[i]数组,然后当i>=k了的时候S[i]/a[i-k],然后代码写完提交发现我没有考虑0的情况。

然后等题解出来发现原来还有逆元这种骚东西。不愧是我,小菜鸡。还是太菜了啥都不知道。

具体看大佬的代码吧,都标注好了的。

当然此处大佬用的是快速幂求逆元。

#include <iostream>
#include <cstdio>
#include <stack>
#include <string>
using namespace std;
typedef long long ll;
const int maxn=200010;
const ll mod=998244353;
ll a[maxn];
//如上求逆元
ll poww(ll a,ll n)
{
    ll res=1;
    while(n>0)
    {
        if(n&1) res=(res*a)%mod;
        a=(a*a)%mod;
        n>>=1;
    }
    return res;
}
// 就是求a^p-2,就这么简单
ll inv(ll a,ll p)
{
    return poww(a,p-2);
}
 
int main()
{
    int n,k;
    cin>>n>>k;
    ll zero=0;//当前长度为k的字段有多少0,我们维护这个变量的意义是,当子段里有0,那么子段的乘积就为0
    ll ans=0;
    ll temp=1;    //temp维护区间内除0以外的数的乘积
    //尺取法
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
        if(!a[i]) zero++;     //如果遇到0,则加一
        else temp=temp*a[i]%mod;  //否则乘以这个数
 
        if(i>=k)
        {
            if(!a[i-k]) zero--; //如果k长度子段第一个元素前一个元素为0,说明我们的区间已经移动过去了
            else temp=temp*inv(a[i-k],mod)%mod; //否则乘以它的逆元,因为0没有逆元
        }
        if(i>=k-1&&!zero) ans=ans>temp?ans:temp;//如果zero=0,则说明该区间里面的数全部大于0,就可以和答案比较了
    }
    printf("%lld",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zust-lms/p/12300265.html