条件反射でいもす法をしたけれど、もっと楽にできた
そして手前味噌ながら類題
問題概要
個の区間 があたえられる。 を満たしている。
この区間が 重に交わっている部分の長さを求めよ。
制約
解法 1:区間の交差
区間 と の交差は実は簡単にかけて
- (左端が で右端が )
になる。面倒な場合分けが要らない!!!
ただし の場合は「交差しない」ということになる。
このことを利用して、 個の区間の交差は
と表せる。これを と表したとき、
- なら、 が答え
- なら、 が答え
となる。
#include <iostream> #include <vector> using namespace std; int main() { int N, M; cin >> N >> M; int left = 1, right = N; for (int i = 0; i < M; ++i) { int a, b; cin >> a >> b; left = max(left, a); right = min(right, b); } cout << max(right - left + 1, 0) << endl; }
解法 2:いもす法
この問題の解説とほぼ同じことをすれば OK。
そして最後に、「出来上がった配列のうち、値が になっている部分を数える」とすればよい。
なお、下のコードで、 については 0-indexed で考えています。一方で、問題文で与えられているのは左閉区間・右閉区間ですが、いもす法を適用するために左閉区間・右開区間にしています。よって、
--l --r ++r
をすることになって、 については結果的に入力のままとしています。
#include <iostream> #include <vector> using namespace std; int main() { int N, M; cin >> N >> M; vector<int> G(N+1, 0); for (int i = 0; i < M; ++i) { int l, r; cin >> l >> r; --l; G[l]++; G[r]--; } for (int i = 0; i < N; ++i) G[i+1] += G[i]; int res = 0; for (int i = 0; i < N; ++i) if (G[i] == M) ++res; cout << res << endl; }