相信大家都理解了题目得意思,就是求一段子段得乘积并取模得最大余数。
思路:尺取法,l代表左端点,r代表右端点。l先不动,r往前扫描,如果成功扫到,有k个非0元素的子段就累成起来,最后把最左端的元素除了,左端点往前移动,l++,再继续扫描。再未达到k个非零元素的子段前,如果遇到0,当前的区间就废了 ,左端点直接到0的下一个位置。继续扫描。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll mod = 998244353; const ll N = 200005; ll a[N]; ll Max = 0;//记录最终结果 ll sum = 1; ll Qpow(ll x,ll k)//快速幂求逆元 { ll ans = 1; while(k) { if(k%2!=0) ans = ans*x%mod; k=k>>1; x=x*x%mod; } return ans; } int main() { ll n,k; cin>>n>>k; for(int i=1;i<=n;i++) { cin>>a[i]; } ll l = 1; //尺取法 ll r = 1; while(r<=n) { if(a[r]) //不是0就累乘直到达到k段子段 { sum=(sum*a[r])%mod;//sum是每一次扫描成功的值 if((r-l+1)%k==0) //达到k子段 { if(sum>Max) Max = sum;//题上要求取最大的 sum = sum*Qpow(a[l],mod-2)%mod;//逆元 ,原本是sum=sum/a[l] 。 //一次扫描成功后,就吧最左端的元素除掉,再继续扫描。当然不能直接除 , //这里需要用到逆元知识,不懂的可以去了解下 ,反正我那个式子就=(a[l]*a[l+1]*..*a[r])/a[l] //我是这样理解的,因为才学,可能有错误的地方,请指出 l++; } } else //再未达到k个非零元素的子段前,如果遇到0,当前的区间就废了 { l = r + 1;// 左端点直接到0的下一个位置 sum = 1;//sum归1 } r++; } cout<<Max<<endl; return 0; }
如果还有不明白的,欢迎提问。其实,虽然我写的代码,但是,我有一点不明白(太菜了),为何,求逆元那里,sum = sum*Qpow(a[l],mod-2)%mod;这里还要取模,这个是我碰对的,没取模就不能过,希望大佬指教。