Official

B - Trapezoid Sum Editorial by tatyam


黒板に書かれている整数は最大で \(10^{11}\) 個になるため、黒板に書かれている整数を \(1\) つずつ足していくと TLE になってしまいます。
そのため、うまくまとめて足すことが必要です。

A. \(1\) 回の操作で書かれる数をまとめる

\(1\) 以上 \(x\) 以下の全ての整数の和は \(\dfrac{x(x+1)}2\) で求めることができます。
これを使うと、

( \(A\) 以上 \(B\) 以下の全ての整数の和 ) \(=\) ( \(1\) 以上 \(B\) 以下の全ての整数の和 ) \(-\) ( \(1\) 以上 \(A-1\) 以下の全ての整数の和 ) \(=\dfrac{B(B+1)}2-\dfrac{A(A-1)}2\)

と求められることがわかります。
これを足すことで、 \(O(N)\) でこの問題を解くことができます。

答えが 32bit 整数に収まらないことに注意してください。

回答例 (C++)

#include <iostream>
using namespace std;
using ll = int64_t;

int main(){
    ll n;
    cin >> n;
    ll ans = 0;
    for(ll i = 0; i < n; i++){
        ll a, b;
        cin >> a >> b;
        ans += b * (b + 1) / 2 - a * (a - 1) / 2;
    }
    cout << ans << endl;
}

回答例 (Python)

n = int(input())
ans = 0
for i in range(n):
    a, b = map(int, input().split())
    ans += b * (b + 1) // 2 - a * (a - 1) // 2
print(ans)

B. 同じ数をまとめる

\(1 \leq A_i \leq B_i \leq 10^6\) なので、ある数が何回黒板に書かれるかが分かれば、合計は高速に求めることができます。

\(cnt[i]=\) ( 黒板に書かれた \(i\) の数 )

で表される配列を考えます。最初は \(cnt[i]=0\) です。
\(1\) 回の操作は、 \(cnt[A]\) から \(cnt[B]\) までに \(1\) を加える操作と考えることができます。
この操作は いもす法 で高速化でき、全体で \(O(N+\max(B))\) で解くことができます。

回答例 (C++)

#include <iostream>
#include <vector>
using namespace std;
using ll = int64_t;

int main(){
    ll n;
    cin >> n;
    vector<ll> cnt(1000002);
    for(ll i = 0; i < n; i++){
        ll a, b;
        cin >> a >> b;
        cnt[a]++;
        cnt[b + 1]--;
    }
    for(ll i = 0; i + 1 < cnt.size(); i++) cnt[i + 1] += cnt[i];
    ll ans = 0;
    for(ll i = 0; i < cnt.size(); i++) ans += cnt[i] * i;
    cout << ans << endl;
}

posted:
last update: