SRM505 Div1 Medium(500) SetMultiples
閾値Tより小さい値は1個ずつSに含まれるかどうかを調べる。
閾値T以上の値は、[A,B], [C,D]の範囲から、[(A+1)/2,B/2],[(C+1)/2,D/2],[(A+2)/3,B/3],[(C+2)/3,D/3],……,[(A+k-1)/k,B/k],[(C+k-1)/k,D/k]を除いた範囲の長さを調べる。T以上と[A,B],[C,D]で+1、[(A+1)/2,B/2],……で-1すると、2となる範囲が答え。
#include <vector> #include <utility> #include <algorithm> using namespace std; class SetMultiples{public: long long smallestSubset( long long A, long long B, long long C, long long D ) { long long ans = 0; long long T = 100000; // T未満 for ( long long i=A; i<=B && i<T; i++ ) if ( B<2*i && C%i!=0 && C/i==D/i ) ans++; for ( long long i=C; i<=D && i<T; i++ ) if ( D<2*i ) ans++; // T以上 vector<pair<long long,int> > P; P.push_back( make_pair(T, 1) ); P.push_back( make_pair(A, 1) ); P.push_back( make_pair(B+1,-1) ); P.push_back( make_pair(C, 1) ); P.push_back( make_pair(D+1,-1) ); for ( long long i=2; B/i>=T; i++ ) P.push_back( make_pair((A+i-1)/i, -1) ), P.push_back( make_pair(B/i+1, 1) ); for ( long long i=2; D/i>=T; i++ ) P.push_back( make_pair((C+i-1)/i, -1) ), P.push_back( make_pair(D/i+1, 1) ); sort(P.begin(),P.end()); int t = 0; for ( int i=0; i<(int)P.size(); i++ ) { if ( t == 2 ) ans += P[i].first-P[i-1].first; t += P[i].second; } return ans; }};