Title

五五五五五(easy)题解

题意简述

有一个长度为 $n$ 的序列 $a$,求对于每一个 $a_l\sim a_r (1\leq l,r\leq n)$,其中从 $a_r$ 开始的连续的 $5$ 的个数(向前找)之和。

思路

我们发现会出现没有 $5$ 的情况,这个时候直接输出 $0$ 就可以了。但是正解思路显然不是这个。

因为 $n\leq 2\times 10^5$ ,所以自然不能 $O(n^2)$ 暴力统计。显然,答案为 $\Sigma_i^{cnt} (pos_i\times len_i+sum_i)$,其中 $cnt$ 为连续的 $5$ 的块数,$len_i$ 为每个连续的 $5$ 的块的长度,$pos_i$ 表示当前块的起始位置,$sum_i$ 表示 $\Sigma_j^{len_i} j\times (len_i - j + 1)$。

那么根据这个公式,我们就很容易得到如下的两个代码:

第一部分,计算 $\Sigma_i^{cnt} (pos_i\times len_i)$。

for(int i=1;i<=n+1;i++){//遍历到n+1,可以统计最后一个5的块 
    if(a[i]==5)//如果当前的ai为5,那么更新长度 
        f[i]=f[i-1]+1;
    else f[i]=0;//如果不是的话,就一直为0 
    if(a[i]==5&&a[i-1]!=5)//如果这是一个块的起点,那么更新起始点的位置(第一个不为5的点) 
        lst=i-1;
    if(a[i]!=5&&a[i-1]==5){//如果这是一个块的结束,那么计算答案 
        len[++ce]=f[i-1];//统计长度 
        ans+=lst*(((len[ce]+1)*len[ce]/2)%Mode)%Mode;//根据公式计算答案 
        ans%=Mode;//取模 
    }
}

第二部分,计算 $\Sigma_i^{cnt}\Sigma_j^{len_i} j\times (len_i - j + 1)$。

for(int i=1;i<=ce;i++){
    for(int j=1;j<=len[i];j++){
        ans+=j*(len[i]-j+1);//根据公式计算如果l在块内部的答案 
        ans%=Mode;//取模 
    }
    ans%=Mode;//还是取模 
//      cout<<len[i]<<" ";
}

AC代码

#include<bits/stdc++.h>
#define ll long long
#define ull usigned long long
using namespace std;
const string TypideName="c";
inline void readc(char &c){
    c=getchar();
    while(c==' '||c=='\n')
        c=getchar();
}inline void writec(char c){putchar(c);}
template<typename T>inline void read(T& x) {
    if(typeid(x).name()==TypideName){char ch;readc(ch);x=ch;return;}
    x = 0; bool f = false; char ch = getchar();
    while (ch < '0' || ch>'9') { if (ch == '-') f = !f; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar(); }
    x = (f ? -x : x); return;
}template<typename T>inline void put(T x) {
    if (x < 0) putchar('-'), x = -x;
    if (x > 9) put(x / 10);
    putchar(x % 10 + '0'); return;
}template<typename T>inline void write(T x) {
    if(typeid(x).name()==TypideName){writec(x);return;}
    put(x);
}
template<typename T,typename... Args>
inline void read(T& x,Args&...x_) {read(x),read(x_...);}
template<typename T,typename... Args>
inline void write(T x,Args...x_){write(x),write(x_...);}
#define N 200005
#define int ll
#define Mode 1000000007
int n,a[N],maxt=-1;
int f[N],len[N],ce,lst;ll ans=0;
inline void work(){
    read(n);
    for(int i=1;i<=n;i++)
        read(a[i]),
        maxt=max(maxt,a[i]);
    for(int i=1;i<=n+1;i++){//遍历到n+1,可以统计最后一个5的块 
        if(a[i]==5)//如果当前的ai为5,那么更新长度 
            f[i]=f[i-1]+1;
        else f[i]=0;//如果不是的话,就一直为0 
        if(a[i]==5&&a[i-1]!=5)//如果这是一个块的起点,那么更新起始点的位置(第一个不为5的点) 
            lst=i-1;
        if(a[i]!=5&&a[i-1]==5){//如果这是一个块的结束,那么计算答案 
            len[++ce]=f[i-1];//统计长度 
            ans+=lst*(((len[ce]+1)*len[ce]/2)%Mode)%Mode;//根据公式计算答案 
            ans%=Mode;//取模 
        }
    }
    for(int i=1;i<=ce;i++){
        for(int j=1;j<=len[i];j++){
            ans+=j*(len[i]-j+1);//根据公式计算如果l在块内部的答案 
            ans%=Mode;//取模 
        }
        ans%=Mode;//还是取模 
    }
    write(ans);
}
signed main(){
    work();
    return 0;
}
posted @ 2023-10-06 10:28  UncleSam_Died  阅读(49)  评论(0)    收藏  举报  来源