SP17247

题面

我的方法好像和大家都不一样诶,那我就写个题解吧。

约定:

\([a,b]\) 为区间 \([a,b]\) 中每个数的数字和的和,\([a,b)\) 为区间 \([a,b)\) 中每个数的数字和的和。

分析:

首先将区间问题转化为前缀和问题,即 \([a,b]=[0,b]-[0,a-1]=[0,b+1)-[0,a)\)

也就是说我们只需要能求出任意的 \([0,n]=[0,n+1)\) 就可以了。

下面考虑如何求 \([0,n)\)

求解:

不难发现,如果我们把 \(n\) 的按每一位拆开,比如如果 \(n=4325\),则显然有 \([0,4325)=[0,4000)+[4000,4300)+[4300,4320)+[4320,4325)\)

形式化地说,如果令 \(n=\sum\limits_{i=0}^{\left\lfloor\lg n\right\rfloor}a_i10^i\,\,(a_i\in\mathbb N^*)\),则必然有:

\[[0,n)=\sum_{i=0}^{\left\lfloor\lg n\right\rfloor}[n-\sum_{j=0}^ia_i,n-\sum_{j=0}^{i-1}a_i) \]

(好像有点太形式化了)

我们考虑如何求 \([43000,43200)\)

\[\begin{aligned} [43000,43200)&=(4+3+0+0+0)+(4+3+0+0+1)+\dots+(4+3+1+9+9) \\&=2\times 100\times(4+3)+2\times(0+1+2+\dots99)+10\times(0+1) \\&=2\times 100\times(4+3)+2\times[0,100)+100\times[0,1] \end{aligned}\]

我们发现,只要预处理求出 \(\{a\},[0,10^i)\)\([0,i]\,(0\le i\le 9)\),然后按从例子中发现的规律,从高往低挨位处理,就可以快速求出 \([0,n)\) 的值了。

代码:

代码中有更明确的计算方式,可能更好理解吧。

#include<bits/stdc++.h>
#define endl '\n'
#define rep(i, s, e) for(int i = s; i <= e; ++i)
#define per(i, s, e) for(int i = s; i >= e; --i)
#define F first
#define S second
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef __int128_t i128;
typedef __uint128_t u128;
typedef pair<int, int> pii;
ll pw10[20], g[10], s0[20]; // pw10[i]: 10的i次幂,g[i]: [0,i]或[0,i+1),s0[i]: [0,10^i)
void init() {
    pw10[0] = 1;
    rep(i, 1, 15) pw10[i] = pw10[i - 1] * 10;
    rep(i, 1, 9) g[i] = g[i - 1] + i;
    s0[1] = 45;
    rep(i, 1, 15) s0[i] = s0[i - 1] * 10 + 45 * pw10[i - 1]; // [0,9]=45
}
ll calc(ll x) {
    ll dg[20] = {}, ans = 0, j = 0;
    while(x) {
        dg[j++] = x % 10;
        x /= 10;
    }
    ll s = 0;
    per(i, j, 1) { // 核心部分
        s += dg[i];
        ans += s * dg[i - 1] * pw10[i - 1];
        ans += dg[i - 1] * s0[i - 1];
        if(dg[i - 1]) ans += g[dg[i - 1] - 1] * pw10[i - 1];
    }
    return ans;
}
int main() {
#ifdef ONLINE_JUDGE
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
#endif
    init();
    int t; cin >> t;
    while(t--) {
        ll a, b; cin >> a >> b;
        cout << calc(b + 1) - calc(a) << endl;
    }
    return 0;
}
posted @ 2023-04-24 20:20  untitled0  阅读(44)  评论(0)    收藏  举报