NTOJ 1012 [RYOI2018ER]想要

给定$n$个$k$维空间的点,以及两个$k$维空间的特殊点,称作$s,t$

要求确定两个数字$r_s,r_t$,使得以$s$为球心的$k$维空间半径为$r_s$的球,和以$t$为球心的$k$维空间半径为$r_t$的球,所框出来的点的并的个数最多

同时有三个常数$k_s,k_t,f$,需要满足$k_s r_s^2+k_t r_t^2 \le f$

$n \le 10^6,k \le 10,x_i \le 10^5,k_h, k_s \le 10^6,f \le 2 \times 10^{18},n \times k \le 2500000$

首先想一个暴力:

不放暴力枚举一下$r_s$,显然只能在所有点到$s$的距离中进行枚举

然后枚举一下$r_t$,之后计算有多少个点被包含

这样做的复杂度是$O(n^3)$,考虑如何优化

首先可以把“计算有多少个点被包含”这样做:将所有点按照和$s$的距离排个序,存到$a_s$数组中,将所有点按照和$t$的距离排个序,存到$a_t$数组中

那么枚举$r_s$就相当于枚举$a_s$的下标$i$,这样的话$1 \sim i$都会被计算到$s$中

当$i$从小到大枚举后,$j$会从大到小不严格递减

那么$ans=i+j-T$,其中$T$表示既被$s$选了,又被$t$选了的点的个数

考虑主席树维护区间本质不同颜色个数那样的套路,开一个$pos$数组,其中$pos_{(a_s)_i}=i$

那么就相当于统计$\forall p \in [1,j]$,有多少个$pos_p \le i$

树状数组维护一下就行了

(当然这题有$O(n \log n + n)$的优秀小常数做法……我比较弱就没写……)

 1 %:pragma GCC optimize(2)
 2 %:pragma GCC optimize("Ofast")
 3 #include <bits/stdc++.h>
 4 using namespace std;
 5 typedef long long ll;
 6 const int N = 1e6 + 10, K = 11;
 7 int n, k, kh, ks; ll f;
 8 int a[K], hom[K], sch[K];
 9 
10 struct FastIO {
11     static const int S = 1e7;
12     int wpos;
13     char wbuf[S];
14     FastIO() : wpos(0) {}
15     inline int xchar() {
16         static char buf[S];
17         static int len = 0, pos = 0;
18         if (pos == len)
19             pos = 0, len = fread(buf, 1, S, stdin);
20         if (pos == len) exit(0);
21         return buf[pos++];
22     }
23     inline ll xuint() {
24         int c = xchar();
25         ll x = 0;
26         while (c <= 32) c = xchar();
27         for (; '0' <= c && c <= '9'; c = xchar()) x = x * 10 + c - '0';
28         return x;
29     }
30     ~FastIO()
31     {
32         if (wpos) fwrite(wbuf, 1, wpos, stdout), wpos = 0;
33     }
34 } io;
35 
36 template<typename T> inline void read(T &x) {
37     char c = x = 0;
38     while(!isdigit(c)) c = getchar();
39     while(isdigit(c)) x = x * 10 + c - '0', c = getchar();
40 }
41 
42 inline ll getdis(int *b) {
43     ll r = 0;
44     for(int i = 1 ; i <= k ; ++ i) r += (ll) (a[i] - b[i]) * (a[i] - b[i]);
45     return r;
46 }
47 
48 int pos[N], bit[N];
49 inline void add(int x, int y) { for( ; x <= n ; x += x & -x) bit[x] += y; }
50 inline int query(int x) { int r = 0; for( ; x ; x -= x & -x) r += bit[x]; return r; }
51 
52 struct T { int id; ll val; } da[N], db[N];
53 bool operator < (T a, T b) { return a.val < b.val; }
54 
55 int main() {
56     freopen("want.in", "r", stdin);
57     freopen("want.out", "w", stdout);
58 //    read(n), read(k), read(f), read(kh), read(ks);
59     n = io.xuint(), k = io.xuint(), f = io.xuint(), kh = io.xuint(), ks = io.xuint();
60     for(int i = 1 ; i <= k ; ++ i) {
61 //        read(hom[i]);
62         hom[i] = io.xuint();
63     }
64     for(int i = 1 ; i <= k ; ++ i) {
65 //        read(sch[i]);
66         sch[i] = io.xuint();
67     }
68     for(int i = 1 ; i <= n ; ++ i) {
69         for(int j = 1 ; j <= k ; ++ j) {
70             a[j] = io.xuint();
71 //            read(a[j]);
72         }
73         da[i] = (T) { i, getdis(hom) }, db[i] = (T) { i, getdis(sch) };
74     }
75     
76     sort(da + 1, da + 1 + n), sort(db + 1, db + 1 + n);
77     
78     for(int i = 1 ; i <= n ; ++ i) pos[da[i].id] = i;    
79     for(int i = 1 ; i <= n ; ++ i) add(pos[db[i].id], 1);
80     
81     int ans = 0;
82     
83     for(int i = n ; i ; -- i) {
84         if(kh * da[i].val <= f || ks * db[i].val <= f) {
85             ans = i;
86             break;
87         }
88     }
89     for(int i = 1, j = n ; i <= n ; ++ i) {
90         if(i + 1 <= n && da[i].val == da[i + 1].val) continue;
91         if(kh * da[i].val > f) break;
92         ll dkb = f - kh * da[i].val;
93         while(j - 1 >= 1 && ks * db[j].val > dkb) add(pos[db[j --].id], -1);
94         if(ks * db[j].val > dkb) break;
95         ans = max(ans, i + j - query(i));
96     }
97     printf("%d\n", ans);
98 }
NTOJ 1012 [RYOI2018ER]想要
posted @ 2018-09-04 22:38  KingSann  阅读(176)  评论(0编辑  收藏  举报