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: