题解:P13702 [NWERC 2023] Chair Dance
LinkCatTree · · 题解
题目本身和解法都很有意思的题喵。
我们发现如果没有发生“抢椅子”,这个题能很简单的维护。具体的,我们可以发现一个人最初的位置
:::info
对于 + x 操作,
对于 * x 操作,
:::
那么我们只需考虑与维护“抢椅子”即可。首先我们发现一个性质:“抢椅子”不会发生超过 感性理解即可我们发现无论何时剩下的人的位置整除 * x 操作,若
这个性质十分良好,我们希望在发生一轮“抢椅子”时能够使用
这个有很多方法维护,这里笔者选择了并查集。具体的,让被抢椅子的人在并查集上的父亲指向抢到椅子的人(这些可以在模拟抢椅子的过程中完成),每次只需要找到
具体实现要注意椅子是
inline int gcd(int x,int y) {
return !y?x:gcd(y,x%y);
}
inline int exgcd(int a,int b,int &x,int &y) {
if(!b) return x=1,y=0,a;
int k=exgcd(b,a%b,y,x);
return y-=a/b*x,k;
}
inline int find(int x) {
return (x==fa[x])?x:(fa[x]=find(fa[x]));
}
int main() {
dt=n=read(),q=read();
for(int i=1;i<=n;i++) fa[i]=i;
auto df=[](int x)->int {return (x<0)?x+n:x;};
auto dg=[](int x)->int {return !x?n:x;};
for(int i=1;i<=q;i++) {
char ch=getchar();
while(ch!='?'&&ch!='+'&&ch!='*') ch=getchar();
if(ch=='+') {
add+=read();
if(add>=n) add-=n;
}
if(ch=='?') {
// x * mul + add = pos
int pos=df(read()-add);
int x,y,g=exgcd(mul,n,x,y);
if(pos%g) printf("-1\n");
else {
int k=dg(((ll)x*(pos/g)%n+n)%n);
printf("%d\n",find(k));
}
}
if(ch=='*') {
int v=read();
if(gcd(v,dt)<2) {
mul=(ll)mul*v%n,add=(ll)add*v%n;
continue ;
}
dt/=gcd(v,dt);
memset(dis,-1,sizeof(int)*(n+2));
memset(from,-1,sizeof(int)*(n+2));
for(int i=1;i<=n;i++) {
if(fa[i]!=i) continue ;
int p=dg(((ll)i*mul+add)%n),q=dg((ll)p*v%n),d=df(q-p);
if(from[q]<0) {dis[q]=d,from[q]=i; continue ;}
if(d<dis[q]) dis[q]=d,from[q]=fa[from[q]]=i;
else fa[i]=from[q];
}
mul=(ll)mul*v%n,add=(ll)add*v%n;
}
}
return 0;
}