题目链接
Atcoder方向
Luogu方向
题目解法
首先可以观察到一个 s i m p l e simple simple 的性质:两个相反数每次移动到的位置也是相反数
同时因为坐标的范围较小,所以可以考虑维护一部分位置的信息,来推出其他与它对称的点的信息
首先维护 l , r l,r l,r,表示当前只维护 l − r l-r l−r 的信息,同时维护 p o s pos pos 表示当前原点所在位置
考虑把位置的移动变成原点的移动,这样每个位置与原点的相对位置是不会发生改变的
如果原点在 l , r l,r l,r 之间,需分情况讨论
- r − p o s > p o s − l r-pos>pos-l r−pos>pos−l,即在原点右边的部分较大,考虑只维护原点右边的部分,舍弃原点左边的部分,只需要将右边的部分指向左边的部分,表示这两个点对称,答案相反即可
- r − p o s < = p o s − l r-pos<=pos-l r−pos<=pos−l,同理
最后考虑 x = p o s x=pos x=pos 的情况,即可以移到原点,只要将与它对称的点都标记可以移到原点即可
#include <bits/stdc++.h>
using namespace std;
const int N(1000100);
int n,m,a[N],ed[N],ans[N];
bool vis[N];
int e[N],h[N],ne[N],idx;
inline int read(){int FF=0,RR=1;char ch=getchar();for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;return FF*RR;
}
void dfs(int u){for(int i=h[u];~i;i=ne[i]){int v=e[i];ans[v]=-ans[u],ed[v]=ed[u];dfs(v);}
}
void add(int a,int b){ e[idx]=b,ne[idx]=h[a],h[a]=idx++;}
int main(){memset(h,-1,sizeof(h));n=read(),m=read();for(int i=1;i<=n;i++) a[i]=read();int l=1,r=1e6,pos=0;for(int i=1;i<=m;i++){int d=read();if(l>pos) pos+=d;else pos-=d;//l,r,pos的相对位置不影响 if(pos<l||pos>r) continue;//l,r不会被割开 if(pos-l<r-pos){//从多的部分指向少的部分,只保存多的部分继续往下做,少的部分通过对称得出 for(int i=l;i<pos;i++) add(2*pos-i,i),vis[i]=1;/*i不可以做开始点*/l=pos+1,ed[pos]=i;}else{for(int i=pos+1;i<=r;i++) add(2*pos-i,i),vis[i]=1;r=pos-1,ed[pos]=i;}}for(int i=l;i<=r;i++) ans[i]=i-pos;for(int i=1;i<=1e6;i++) if(!vis[i]) dfs(i);for(int i=1;i<=n;i++)if(ed[a[i]]) printf("Yes %d\n",ed[a[i]]); else printf("No %d\n",ans[a[i]]);return 0;
}