小白月赛E题个人题解

看到数据范围可见n^2必然会超时,那么就不能用暴力的思路处理,我们必须思考以下两个问题。

怎样合理的枚举?

注意到F数组的第n行的贡献为 a[n] 记为 C[n]

第n-1行的贡献为 a[n-1] + a[n-1] * a[n] = a[n-1] * (1 + a[n])

我们发现,从n行往上枚举,设第 i 行的贡献为 C[i] ,则 C[i] = a[i] * (1 + C[i+1])

那么将所有的 C[i] 加起来就是答案, 至此我们可以O(n)的进行枚举

如何处理25的倍数?

对于构成每一行贡献的和式(即C[i]中的加项),有些数是25的倍数,有些不是,我们不能逐一判别。

但我们能通过预处理的办法先把每个 a[i] 变为只是 5 在其中的次幂只是 0 或 1

这启发我们, 是否可以对答案维护两个项 t0 和 t1

分别代表在 i+1 行的贡献中不是 5 的倍数的那些加项的和,以及是5的倍数的加项

这样在计算C[i] 时只需要维护好 t0 和 t1 即可

考虑维护 t0 和 t1

当 a[i] % 5 !=0 时,没有出现25的倍数,则:

t0 = (t0 + 1) * a[i] , t1 = t1 * a[i]

否则, t1 * a[i] 后是25的倍数, 应该乘25的逆元, t0 * a[i] 后是5的倍数, 在统计答案后交换t0,t1即可

t0 = (t0 + 1) * a[i] , t1 = t1 * a[i] * 逆25, swap(t0,t1)

最后遍历统计答案即可

处理部分代码如下

    ll t0=0,t1=0;
    if(a[n]%5==0) t1+=a[n];
    else t0+=a[n];
    
    ll res=a[n];
    ll mul=quipow(25,M-2,M);
    for(int i=n-1;i>=1;--i)
    {
        t0=(t0+1)*a[i]%M,t1=t1*a[i]%M;//1加在t0 , 因为 1 不是5的倍数
        if(a[i]%5==0) 
        {
            t1=t1*mul%M;
            res=(res+t0+t1)%M;
            swap(t0,t1);
        }
        else res=(res+t0+t1)%M;
    }

题外话,赛时把mul = quipow(25,M-2,M)写成 mul = (25,M-2,M) 一小时没看出来,还是太菜了

最后,第一次写题解,难免有疏漏或是表达失当,欢迎指正,希望对你有所帮助。