#line 1 "Main.cpp" #include #include #include #include #include #include #line 2 "nachia\\multi-dimensional\\two-d-rectangle-query.hpp" #line 4 "nachia\\multi-dimensional\\two-d-rectangle-query.hpp" #include #line 7 "nachia\\multi-dimensional\\two-d-rectangle-query.hpp" namespace nachia{ template struct TwoDRectangleQuery{ private: struct BitVectorRank { using u64 = std::uint64_t; using u32 = std::uint32_t; static u32 popcountll(u64 c){ #ifdef __GNUC__ return __builtin_popcountll(c); #else c = (c & (~0ull/3)) + ((c >> 1) & (~0ull/3)); c = (c & (~0ull/5)) + ((c >> 2) & (~0ull/5)); c = (c & (~0ull/17)) + ((c >> 4) & (~0ull/17)); c = (c * (~0ull/255)) >> 56; return c; #endif } std::vector> a; BitVectorRank(const std::vector& b = {}){ int n = b.size(); a.assign(n/64 + 1, std::make_pair((u64)0, (u32)0)); auto p = b.begin(); u32 sum = 0; u64 tmp = 0; for(int i=0; i<=n; i+=64){ tmp = 0; int maxd = std::min(n - i, 64); for(int d=0; d> 6]; return (u32)(popcountll(b & ~(~u64(0) << (i & 63)))) + s; } bool get(std::uint32_t i) const { return (a[i >> 6].first >> (i & 63)) & 1; } }; int n; int N; int logN; std::vector Xsorted; std::vector Ysorted; std::vector rankX; std::vector> Idx; std::vector Z; std::vector L; public: TwoDRectangleQuery(const std::vector>& pos){ n = pos.size(); std::vector sortIY(n); for(int i=0; i sortIX(n); rankX.resize(n); for(int i=0; i(n,-1)); L.resize(logN); Z.resize(logN); for(int i=0; i=0; i--){ std::vector Lbuf(n,0); auto& preList = Idx[i+1]; int z = ((n >> (i+1)) << i) + std::min(1< get_update_points(int v) const { std::vector res(logN+1); int p = rankX[v]; int d = logN; while(d > 0){ res[d] = { d,p }; d--; if(L[d].get(p)) p = L[d].rank(p); else p = Z[d] + p - L[d].rank(p); } res[d] = {d,p}; return res; } struct Query{ int d,l,r; }; std::vector get_ranges_from_idx(int xl, int xr, int yl, int yr){ std::vector res; struct Search{ int i, xa, xb, ys, yt; }; std::vector Q; res.reserve((logN+1)*2); Q.reserve((logN+1)*2); Q.push_back({ logN,0,n,yl,yr }); for(int i=0; i<(int)Q.size(); i++){ auto p = Q[i]; if(p.xa == p.xb) continue; if(xr <= p.xa || p.xb <= xl) continue; if(xl <= p.xa && p.xb <= xr){ res.push_back({ p.i, p.ys, p.yt }); continue; } p.i--; int nxs = L[p.i].rank(p.ys), nxt = L[p.i].rank(p.yt); Q.push_back({ p.i,p.xa,p.xa+(1< get_ranges(PosX xl, PosX xr, PosY yl, PosY yr){ return get_ranges_from_idx( lower_bound(Xsorted.begin(),Xsorted.end(),xl) - Xsorted.begin(), lower_bound(Xsorted.begin(),Xsorted.end(),xr) - Xsorted.begin(), lower_bound(Ysorted.begin(),Ysorted.end(),yl) - Ysorted.begin(), lower_bound(Ysorted.begin(),Ysorted.end(),yr) - Ysorted.begin() ); } }; } // namespace nachia #line 8 "Main.cpp" using namespace std; using i32 = int32_t; using u32 = uint32_t; using i64 = int64_t; using u64 = uint64_t; #define rep(i,n) for(int i=0; i<(int)(n); i++) const i64 INF = 1001001001001001001; using Modint = atcoder::static_modint<998244353>; int main(){ int N, K; cin >> N >> K; i64 L, P; cin >> L >> P; L++; vector> A(N); rep(i,N) cin >> A[i].first >> A[i].second; vector>> S, T; S = T = {{{0,0}}}; for(auto [xa,xb] : A){ vector>> tmp(S.size()+1); rep(s,S.size()) for(auto [a,b] : S[s]){ tmp[s].emplace_back(a, b); tmp[s+1].emplace_back(a+xa, b+xb); } swap(S, tmp); swap(S, T); } i64 ans = 0; vector> Tsum; rep(Ti, T.size()){ int Si = K - Ti; if(Si < 0) continue; if((int)S.size() <= Si) Si = S.size()-1; copy(T[Ti].begin(), T[Ti].end(), back_inserter(Tsum)); auto TwoD = nachia::TwoDRectangleQuery(Tsum); for(auto [a,b] : S[Si]){ for(auto q : TwoD.get_ranges(-INF, L-a, P-b, INF)) ans += q.r - q.l; } } cout << ans << '\n'; return 0; } struct ios_do_not_sync{ ios_do_not_sync(){ ios::sync_with_stdio(false); cin.tie(nullptr); } } ios_do_not_sync_instance;