IOI 2007 Pairs
可以考虑三个情况:
若B=1:
这其实好像没什么好说的?lower_bound就可以轻轻松松30分
code:
void solve1(){ for(int i=0;i<N;i++){ std::cin>>a[i]; } sort(a,a+N); i64 ans=0; for(int i=0;i<N;i++){ int lst=lower_bound(a,a+N,a[i]-D)-a; ans+=i-lst; } std::cout<<ans<<'\n'; }
若B=2:
这就需要一些观察了:
考虑分成四个式子可以发现到 $(x,y)$到$(a,b)$的距离为:
if $x-a \geq 0$ and $y-b \geq 0$, $dis = x-a+y-b = (x+y)-(a+b)$
if $x-a < 0$ and $y-b \geq 0$, $dis = a-x+y-b = (a-b)-(x-y)$
if $x-a \geq 0$ and $y-b < 0$, $dis = x-a+b-y = (x-y)-(a-b)$
if $x-a < 0$ and $y-b < 0$, $dis = a-x+b-y = (a+b)-(x+y)$
$(x+y,x-y)$ 和 $(a+b,a-b)$的切比雪夫距离 $max(|(x+y)-(a+b)|, |(x-y)-(a-b)|)$ = $(x,y)$ 和 $(a,b)$ 的曼哈顿距离
结论:转换成$(x+y,x-y)$然后求矩阵$[x+y-d,x-y+d]$ 至 $[x+y,x-y+d]$ 的和。
维护双指针然后利用一个树状结构来维护区间值就可以了.
code:
i64 tr[NN<<1]; void update(int x,i64 v){ x+=NN; for(;x;x=x/=2){ tr[x]+=v;} } i64 get(int x,int y){ x+=NN; y+=NN; i64 res=0; while(x<=y){ if(x%2==1) res+=tr[x++]; if(y%2==0) res+=tr[y--]; x/=2; y/=2; } return res; } void solve2(){ vector<int> pos[75000*2+500]; i64 ans=0; for(int i=0;i<N;i++){ std::cin>>x[i]>>y[i]; pos[x[i]+y[i]].push_back(x[i]-y[i]+M); } for(int i=2;i<=2*M;i++){ for(auto &u:pos[i]){ ans+=get(max(0,u-D),min(2*M,u+D)); update(u,1); } if(i-D<=0) continue; for(auto &u:pos[i-D]) update(u,-1); } std::cout<<ans<<'\n'; }
若B=3: 我本人是不太会的但是看了别人的讲解,大概是拆成八个式子然后利用数值很小的原因,开桶然后就利用类似B=2的方式去解。
以下代码只能过B=1/2:
有时间的话我会修改成B=1/2/3
/* Problem: IOI 2007 Pairs When: 2023-11-16 14:54:19 Author: Ning07 */ #include<bits/stdc++.h> using namespace std; using i64=long long; constexpr int NN=2e5; int N,B,M,D,a[NN],x[NN],y[NN]; void solve1(){ for(int i=0;i<N;i++){ std::cin>>a[i]; } sort(a,a+N); i64 ans=0; for(int i=0;i<N;i++){ int lst=lower_bound(a,a+N,a[i]-D)-a; ans+=i-lst; } std::cout<<ans<<'\n'; } i64 tr[NN<<1]; void update(int x,i64 v){ x+=NN; for(;x;x=x/=2){ tr[x]+=v;} } i64 get(int x,int y){ x+=NN; y+=NN; i64 res=0; while(x<=y){ if(x%2==1) res+=tr[x++]; if(y%2==0) res+=tr[y--]; x/=2; y/=2; } return res; } void solve2(){ vector<int> pos[75000*2+500]; i64 ans=0; for(int i=0;i<N;i++){ std::cin>>x[i]>>y[i]; pos[x[i]+y[i]].push_back(x[i]-y[i]+M); } for(int i=2;i<=2*M;i++){ for(auto &u:pos[i]){ ans+=get(max(0,u-D),min(2*M,u+D)); update(u,1); } if(i-D<=0) continue; for(auto &u:pos[i-D]) update(u,-1); } std::cout<<ans<<'\n'; } void solve3(){ std::cout<<"?\n"; } int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); std::cin>>B>>N>>D>>M; if(B==1) solve1(); else if(B==2) solve2(); else if(B==3) solve3(); }
$+M$是为了更好地询问, $y-d$不会成负数
标签:Pairs,NN,int,geq,pos,i64,2007,IOI From: https://www.cnblogs.com/yonglicp/p/17846334.html