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 }