牛客寒假训练营|牛客寒假训练营 4 C 子段乘积

题目要求 链接:https://ac.nowcoder.com/acm/contest/3005/C
来源:牛客网
题目描述
给出一个长度为 n 的数列 a1,a2,…,ana_1,a_2,\ldots,a_na1?,a2?,…,an?,求其长度为 k 的连续子段的乘积对 998244353 取模余数的最大值。
输入描述:
第一行两个整数n,k。
第二行n个整数,a1,a2,…,ana_1,a_2,\ldots,a_na1?,a2?,…,an?。
输出描述:
输出一个整数,代表最大余数。
示例1
输入
复制
5 3
1 2 3 0 8
输出
复制
6
说明
1?2?3mod??998244353=6123\mod 998244353=61?2?3mod998244353=6
备注:
1≤k≤n≤2?1051 \le k \le n \le 2*10^51≤k≤n≤2?105
0≤ai<9982443530 \le a_i <9982443530≤ai?<998244353
解题思路 【牛客寒假训练营|牛客寒假训练营 4 C 子段乘积】在对数组遍历时,要遇到一种情况,就是子段的长度大于要求的k段时,要除于a[i-k],又因为对ss取过模,一个取过模的数不能直接除一个数必须取逆元,所以不能简单地相除,逆元可以用费马小定理得到,即a^(p-1)≡1(mod p) 又因为a^(p-2) = (a^(p-1))* a(-1)则a(p-2)≡ a^(-1)(mod p),代码如下:

#include #include using namespace std; #define ll long long const ll maxn=2e5+7; const ll mod=998244353; ll a[maxn]; ll n,k; ll fema(ll m,ll n){//用快速幂来求m^n ll sum1=1; while(n>0){ if(n&1) sum1=(sum1*m)%mod; m=(m*m)%mod; n>>=1; } return sum1; }int main() { scanf("%lld%lld",&n,&k); ll i,sum,ss; i=1; sum=0; ss=1; //所求结果和当前段的乘积 for(int ii=1; ii<=n; ii++) scanf("%lld",&a[ii]); int nu=0; //当前段0的个数 for(int i=1; i<=n; i++){ if(a[i]==0)nu++; else ss=(ss*a[i])%mod; if(i>=k+1){ if(a[i-k]==0) nu--; //第前K个为0,不在当前段里,nu减掉,ss不用除 else ss=(ss*fema(a[i-k],mod-2))%mod; //用费马小定理来表示s=s/a[i-k]%mod,因为s取过模,所以无法直接除其他数 } if(nu==0&&i>=k)//说明当前段长一定为K sum=max(sum,ss); } printf("%lld\n",sum); return 0; }

    推荐阅读