給定平面上的n個點,記為a
1...na_
a1...n
現在給出q組詢問,每次給出乙個向量p,你需要找乙個區間[l,
r]
[l,r]
[l,r
],使得2∑i
=lrs
δopa
i2\sum\limits_^s_
2i=l∑r
sδo
pai
最大,輸出這個最大值。
n<=100000,q<=1000000,座標絕對值<=1e9
把每個點看做乙個向量,如果我們把所有的區間的和向量提出來,那麼顯然最大的那個一定在凸包上。
但直接做凸包是o(n
2logn
)o(n^2\log n)
o(n2
logn
)的,顯然不行
我們考慮分治計算這個凸包。
記當前分治區間為[l,
r]
[l,r]
[l,r
],我們需要求出所有左右端點在[l,
r]
[l,r]
[l,r
]內的所有區間[x,
y]
[x,y]
[x,y
]的和向量的凸包。
如果x
<=y
<=m
id
x<=y<=mid
x<=y
<=m
id或m id
<
x<=y
midmi
d<
x<=y
,那麼直接分治兩邊
我們只需要考慮跨過的情況。
可以發現跨過的都能分成[x,
mid]
+[mi
d+1,
y]
[x,mid]+[mid+1,y]
[x,mid
]+[m
id+1
,y],實際上就是左邊右端點為mid和右邊左端點為mid+1的兩部分的閔可夫斯基和(即兩個點集兩兩座標相加)。
有結論,兩個凸包的閔可夫斯基和的凸包,總點數是o(原凸包點數和),並且新凸包的邊斜率和長度都會是原本兩個凸包上的某條邊。
那麼我們直接暴力求出這兩個凸包,各找到最左下的點,然後類似歸併排序的掃一遍就完成了凸包的合併。
這樣我們最後得到了o(n
)o(n)
o(n)
個凸包,總點數和是o(n
logn)
o(n\log n)
o(nlogn)
的。凸包並?
不需要,我們直接把o(n
logn)
o(n\log n)
o(nlogn)
個凸包拉出來暴力再建一次即可。
查詢的時候,我們可以把所有詢問極角排序,顯然最優點在凸包上是單調的,直接用個指標掃(可以用於詢問向量的叉積變號處來判斷)
也可以對於每個詢問在凸包上二分。
實現細節較多。
複雜度o(n
log2n
)o(n\log^2 n)
o(nlog2n
)
#include
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
typedef
long
long ll;
const
int n=
100005
;const
double pi=
acos(-
1);using
namespace std;
int n,q;
struct node
}ask[n*10]
,ap[n]
,ar[
20*n]
;node operator+(
const node &x,
const node &y)
node operator-(
const node &x,
const node &y)
ll operator*(
const node &x,
const node &y)
node now;
ll dis
(const node &x)
bool
cmp(node x,node y)
int num,ds[
10*n]
;double ag[n*10]
;bool
cmp2
(int x,
int y)
#define nxt(k) ((k==top)?1:k+1)
#define lst(k) ((k==1)?top:k-1)
ll ans[
10*n]
;int top;
int st2[
20*n]
,st[
20*n]
;void
get(node *ar,
int num)
}node u1[n]
,u2[n]
;void
doit
(int l,
int r)
int mid=
(l+r)
>>1;
doit
(l,mid)
,doit
(mid+
1,r)
; u1[1]
=ap[mid]
;fod
(i,mid-
1,l) u1[mid-i+1]
=u1[mid-i]
+ap[i]
;get
(u1,mid-l+1)
; st2[0]
=top;
fo(i,
1,top) st2[i]
=st[i]
; u2[1]
=ap[mid+1]
;fo(i,mid+
2,r) u2[i-mid]
=u2[i-mid-1]
+ap[i]
;get
(u2,r-mid)
; st[0]
=top;
st[++st[0]
]=st[1]
,st2[
++st2[0]
]=st2[1]
;int x=
1,y=1;
while
(x||y)}
ll calc
(int mx,
int i)
intmain()
while
(calc
(mx,ds[i]
)<=0||
(calc
(mx,ds[i]
)>=0&&
calc
(lst
(mx)
,ds[i]
)>0)
) mx=
nxt(mx);
ans[ds[i]
]=ask[ds[i]
]*ar[st[mx]];
}fo(i,1
,q)printf
("%lld\n"
,ans[i]);
}
JZOJ 交換 模擬
給出字串s和字串t,現在你要把s的某乙個字元和t的某乙個字元交換,使得交換之後的s至少要有三個連續相同的字元,交換之後的t也要有三個連續相同的字元。問有多少種不同的交換方式。第一行,乙個字串s。s只含有 r g b 三種字元,長度不超過50,不小於3。而且s任意兩個相鄰的字元都不相同。第二行,乙個字...
JZOJ 規律 遊戲
有一堆金塊,king和貓老大輪流抽金塊,每次抽的個數必然是2的次方冪,求勝利 抽走最後一塊 的是誰 三行每行乙個數 n 0對於每局,如果 king 必勝則輸出一行 king will win.否則第一行輸出 maolaoda willwin.第二行輸出他第一次拿的最小數量。8 42maolaoda ...
JZOJ 禮物 數論
聖誕節這天,某商店準備了n個禮品盒,分別用整數1 n進行編號。其中,編號為1的盒子中有乙個糖果,編號為2的盒子中有2個糖果,編號為n的盒子中有n個糖果。這天一早,中山幼兒園的k個小朋友一起來到這間商店。作為當天的第一批顧客,這些小朋友可以從這n個禮品盒中選出兩個拿走。小朋友們商量了一會兒後決定,他們...