『题解』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;
}