用户工具

站点工具


2020-2021:teams:legal_string:组队训练比赛记录:contest1

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录 前一修订版
后一修订版
前一修订版
2020-2021:teams:legal_string:组队训练比赛记录:contest1 [2020/05/11 17:17]
lgwza 创建
2020-2021:teams:legal_string:组队训练比赛记录:contest1 [2021/07/11 10:01] (当前版本)
jxm2001 ↷ 页面2020-2021:teams:legal_string:contest1被移动至2020-2021:teams:legal_string:组队训练比赛记录:contest1
行 1: 行 1:
-abc+[[https://​codeforces.com/​gym/​102569|比赛链接]] 
 + 
 +====== 题解 ====== 
 + 
 +===== A. Array'​s Hash ===== 
 + 
 +=== 题意 === 
 + 
 +给定一个长度为$n$的数组,这么定义该数组的哈希值:每次从数组开头取出两个数,将后一个数减去前一个数得到的数值放入数组开头,如此重复,直到数组中只剩下一个数,最后这个数便为数组的哈希值。现在有$m$次操作,每次操作把一段区间的数加上$v$,要求输出每次操作后数组的哈希值 
 + 
 +===题解=== 
 + 
 +显然数组的哈希值为$\sum_{i=1}^n{\left(-1\right)^\left(n-i\right)\times a_i}$ 
 + 
 +因此当区间左右端点奇偶性相同时对哈希值无贡献,奇偶性不同时如果区间左端点与$n$奇偶性相同则哈希值加$v$,否则减$v$ 
 + 
 +时间复杂度$O\left(n+m\right)$ 
 + 
 +===== B. Bonuses on a Line ===== 
 + 
 +=== 题意 === 
 + 
 +数轴上有 $n$ 份奖金,每份奖金的坐标为 $x_i$ ,总共有 $t$ 秒的时间,每秒可走 $1$ 的距离。初始在原点 $0$ 位置,问最多能获得多少份奖金? 
 + 
 +=== 题解 === 
 + 
 +先向某一方向跑,然后再折返跑向另一方向。例如先向负方向跑,在每份奖金处,利用二分查找,找到能够折返跑到正方向的奖金的最大份数即可。 
 + 
 +时间复杂度 $O\left(n\log n\right)$ 
 + 
 +=== 代码 === 
 + 
 +<code cpp> 
 + 
 +#​include<​bits/​stdc++.h>​ 
 +using namespace std; 
 +const int N=200005; 
 +typedef long long ll; 
 +vector<​ll>​neg;​ 
 +vector<​ll>​pos;​ 
 +int main(){ 
 + ll n,t; 
 + scanf("​%lld %lld",&​n,&​t);​ 
 + for(ll i=1;​i<​=n;​i++){ 
 + ll x; 
 + scanf("​%lld",&​x);​ 
 + if(x<​0) neg.push_back(-x);​ 
 + else pos.push_back(x);​ 
 +
 + reverse(neg.begin(),​neg.end());​ 
 + neg.push_back(1e15);​pos.push_back(1e15);​ 
 + ll maxx=0; 
 + for(ll i=0;​i<​neg.size()-1;​i++){ 
 + if(t>​=neg[i]) maxx=max(maxx,​i+1);​ 
 + ll left=t-2*neg[i];​ 
 + ll p=upper_bound(pos.begin(),​pos.end(),​left)-pos.begin()-1;​ 
 + if(p>​=0) maxx=max(maxx,​i+1+p+1);​ 
 +
 + for(ll i=0;​i<​pos.size()-1;​i++){ 
 + if(t>​=pos[i]) maxx=max(maxx,​i+1);​ 
 + ll left=t-2*pos[i];​ 
 + ll p=upper_bound(neg.begin(),​neg.end(),​left)-neg.begin()-1;​ 
 + if(p>​=0) maxx=max(maxx,​i+1+p+1);​ 
 +
 + printf("​%lld",​maxx);​ 
 + return 0; 
 +
 + 
 +</​code>​ 
 + 
 +===== C. Manhattan Distance ===== 
 + 
 +===题意=== 
 + 
 +在直角坐标系中给定$n$整点$\left(-10^8\le x_i,y_i\le 10^8\right)$,可以得到$\frac{n\times \left(n-1\right)}{2}$个点对,将所有点对的哈密顿距离排序,要求输出第k大的哈密顿距离$\left(2\le n\le 100000,1\le k\le \frac{n\times \left(n-1\right)}{2}\right)$ 
 + 
 +===题解=== 
 + 
 +大概思路为二分答案$d$,统计哈密顿距离$\le d$的点对个数 
 + 
 +首先,将坐标系顺时针旋转$45$度,放大$\sqrt{2}$倍,所以所有点坐标变为$\left(x-y,​x+y\right)$,与某个点哈密顿距离$\le d$转化为在以该点为中心的边长为$2d$的网格正方形中 
 + 
 +考虑用滑动窗口+树状树组统计答案,具体过程见代码 
 + 
 +时间复杂度$O\left(\log\left(4\times 10^8\right) ​ n\log n\right)$ 
 + 
 +===代码=== 
 + 
 +<code cpp> 
 +#include <​iostream>​ 
 +#include <​cstdio>​ 
 +#include <​cstdlib>​ 
 +#include <​algorithm>​ 
 +#include <​cstring>​ 
 +#include <​cctype>​ 
 +#define _for(i,a,b) for(int i=(a);​i<​(b);​++i) 
 +#define _rep(i,a,b) for(int i=(a);​i<​=(b);​++i) 
 +#define mem(a,b) memset(a,​b,​sizeof(a)) 
 +using namespace std; 
 +typedef long long LL; 
 +inline int read_int(){ 
 + int t=0;bool sign=false;​char c=getchar();​ 
 + while(!isdigit(c)){sign|=c=='​-';​c=getchar();​} 
 + while(isdigit(c)){t=(t<<​1)+(t<<​3)+(c&​15);​c=getchar();​} 
 + return sign?​-t:​t;​ 
 +
 +inline LL read_LL(){ 
 + LL t=0;bool sign=false;​char c=getchar();​ 
 + while(!isdigit(c)){sign|=c=='​-';​c=getchar();​} 
 + while(isdigit(c)){t=(t<<​1)+(t<<​3)+(c&​15);​c=getchar();​} 
 + return sign?​-t:​t;​ 
 +
 +#define lowbit(x) (x)&​(-x) 
 +const int MAXN=1e5+5;​ 
 +struct Node{ 
 + int x,y; 
 + bool operator < (const Node &​b)const{ 
 + return x<​b.x||(x==b.x&&​y<​b.y);​ 
 +
 +}node[MAXN];​ 
 +int n,​m,​c[MAXN],​Y[MAXN];​ 
 +LL k; 
 +void add(int pos,int v){ 
 + while(pos<​=n){ 
 + c[pos]+=v;​ 
 + pos+=lowbit(pos);​ 
 +
 +
 +int query(int pos){ 
 + int ans=0; 
 + while(pos){ 
 + ans+=c[pos];​ 
 + pos-=lowbit(pos);​ 
 +
 + return ans; 
 +
 +LL Count(int d){ 
 + mem(c,​0);​ 
 + LL ans=0; 
 + for(int i=1,​j=1;​i<​=n;​i++){ 
 + while(j<​i&&​node[i].x-node[j].x>​d){ 
 + int pos=lower_bound(Y+1,​Y+m,​node[j].y)-Y;​ 
 + add(pos,​-1);​ 
 + j++; 
 +
 + int pos1=upper_bound(Y+1,​Y+m,​node[i].y+d)-Y-1;​ 
 + int pos2=lower_bound(Y+1,​Y+m,​node[i].y-d)-Y-1;​ 
 + int pos3=lower_bound(Y+1,​Y+m,​node[i].y)-Y;​ 
 + ans+=query(pos1)-query(pos2);​ 
 + add(pos3,​1);​ 
 +
 + return ans; 
 +
 +int main() 
 +
 + n=read_int(),​k=read_LL();​ 
 + int x,y; 
 + _rep(i,​1,​n){ 
 + x=read_int(),​y=read_int();​ 
 + node[i].x=x-y,​node[i].y=x+y;​ 
 + Y[i]=x+y;​ 
 +
 + sort(node+1,​node+n+1);​ 
 + sort(Y+1,​Y+n+1);​ 
 + m=unique(Y+1,​Y+n+1)-Y;​ 
 + int lef=1,​rig=4e8,​mid,​ans=-1;​ 
 + while(lef<​=rig){ 
 + mid=lef+rig>>​1;​ 
 + if(Count(mid)<​k) 
 + lef=mid+1;​ 
 + else{ 
 + ans=mid;​ 
 + rig=mid-1;​ 
 +
 +
 + cout<<​ans;​ 
 + return 0; 
 +
 +</​code>​ 
 + 
 +===== D. Lexicographically Minimal Shortest Path ===== 
 + 
 +===== E. Fluctuations of Mana ===== 
 + 
 +签到题 
 +===== F. Moving Target ===== 
 + 
 +===== G. Nuts and Bolts ===== 
 + 
 +===== H. Tree Painting ===== 
 + 
 +===== I. Sorting Colored Array ===== 
 + 
 +===== J. The Battle of Mages ===== 
 + 
 +===== K. Table ===== 
 + 
 +===== L. The Dragon Land ===== 
 + 
 +===== M. Notifications ===== 
 + 
 +签到题 
 + 
 +====== 总结 ======
2020-2021/teams/legal_string/组队训练比赛记录/contest1.1589188659.txt.gz · 最后更改: 2020/05/11 17:17 由 lgwza