『题解』Luogu P8577 [CoE R5] 暴龙的白菜

题目传送门

题目大意

给定一个字符串,由 \(1\)\(\texttt{1}\)\(2\)\(\texttt{2}\)\(3\)\(\texttt{3}\)\(4\)\(\texttt{4}\)\(5\)\(\texttt{5}\)\(6\)\(\texttt{6}\)\(7\)\(\texttt{7}\)\(8\)\(\texttt{8}\)\(9\)\(\texttt{9}\)\(10\)\(\texttt{10}\)……以此类推,依次拼接而成。

询问字符串第 \(l\) 位到第 \(r\) 位的数字之和。

\(1\le T\le 10^5\)\(1\le l\le r\le 10^6\)

思路

有一个只用了前缀和的很暴力的解法。

先用 \(\text{string}\) 预处理出数据范围内的字符串,时间复杂度可以接受。

由于题目是要求和,所以用一个前缀和数组 \(a\) 来存 \(s\) 的数字前缀和。对于 \(i\)\(a_i=\sum\limits^{i}_{j=1}s_j-\text{'0'}\),此时对于询问操作,答案即为 \(a_r-a_{l-1}\)。前缀和不懂的可以参考一下这里

代码

#include <iostream>
#include <algorithm>
using namespace std;
template<typename T=int>
inline T read(){
    T X=0; bool flag=1; char ch=getchar();
    while(ch<'0' || ch>'9'){if(ch=='-') flag=0; ch=getchar();}
    while(ch>='0' && ch<='9') X=(X<<1)+(X<<3)+(ch^48),ch=getchar();
    if(flag) return X;
    return ~(X-1);
}

template<typename T=int>
inline void write(T X){
    if(X<0) putchar('-'),X=~(X-1);
    T s[20],top=0;
    while(X) s[++top]=X%10,X/=10;
    if(!top) s[++top]=0;
    while(top) putchar(s[top--]+'0');
    putchar('\n');
}

const int N=1e6+5;
int t,l,r;
int x;
string s,ss;
int a[N];

// 预处理字符串及前缀和
void init(){
    s+="0",x=1; // s 第一位空着,x 为当前已经加入字符串的数子
    while(s.size()<N){ // 一次循环加入 x 
        int tt=x;
        while(tt) ss+=tt%10+'0',tt/=10;
        reverse(ss.begin(),ss.end());
        for(int i=1; i<=x && s.size()<N; i++)
            s+=ss;
        ss.clear();
        x++;
    }
    for(int i=1; i<N; i++)
        a[i]+=a[i-1]+s[i]-'0';
}

int main(){
    init();
    t=read();
    while(t--){
        l=read(),r=read();
        write(a[r]-a[l-1]);
    }
    return 0;
}
posted @ 2022-10-18 21:05  仙山有茗  阅读(72)  评论(0编辑  收藏  举报