P5582 【SWTR-01】Escape
记 \(b\) 为可用步数序列,长度为 \(m\)。
考虑必要性,即每个点都能通过 \(b\) 的线性组合在模 \(n\) 意义下表示出来。
即 \(b_1x_1+b_2x_2+...+b_mx_m+nx_{m+1}\) 能表示出来 \([0,n)\) 中的每个数,这一部分根据裴蜀定理可得。
这个条件可能是充要的,考虑证明。
定理 31.20:
对于任意正整数 \(a\) 和 \(n\),若 \(d=\gcd(a,n)\),则在 \(Z_n\) 中,\(<a>=<d>\)
引理
环大小为 \(n\),若初始在位置 \(p\),每次跳 \(k\) 步,\(k|n\),则到达的位置一定是 \(x\equiv p \pmod{k}\)。
证明:考虑原先到达的位置 \(x\equiv 0 \pmod{k}\),初始位置在 \(p\) 可看做初始位置在 \(0\),跳完后再向右跳一次 \(p\) 步,因为跳 \(k\) 步能取遍且互不相同的位置 \(x\in[0,n),k|x\),所以你再向右跳显然也能取遍,且互不相同。
考虑先跳 \(b_1\),即记 \(d=\gcd(b_1,n)\),跳完了,\(d,2d \ ... \ (n/d-1)d,0\),那么考虑只要每次跳完这样的一个循环,能够位移到组内另一个地方即可。这样每一次跳到的都是不一样的。
即问题变成了 \(b_2,b_3 \ ... \ b_m\) 跳完 \([0,d)\),考虑结构一样,如此操作下去,最终变成 \(b_m\) 跳完 \([0,\gcd(n,b_1,b_2\ ... \ b_{m-1}))\),显然在 \(Z_{\gcd(n,b_1,b_2\ ... \ b_{m-1})}\) 中,\(|<b_m>|=\gcd(n,b_1,b_2\ ... \ b_{m-1})\),因此可以跳完。然后子问题可以完成,则上级问题推回去也可以完成。
#include <bits/stdc++.h>
#define ll long long
#define pb push_back
using namespace std;
const int N=(int)(1e6+5);
bool vis[N];
int n,m;
int gcd(int x,int y) {
return !y?x:gcd(y,x%y);
}
void sol() {
cin>>n>>m;
for(int i=1;i<=n;i++) vis[i]=0;
for(int i=1;i<=m;i++) {
int x; cin>>x; vis[x]=1;
}
int qwq=0;
for(int i=1;i<=n;i++) {
if(vis[i]) continue ;
if(!qwq) qwq=gcd(i,n);
else qwq=gcd(qwq,gcd(i,n));
}
if(!qwq) {
cout<<"-1\n"; return ;
}
for(int i=1;i<=n;i++) {
if(i%qwq!=0) {
cout<<"-1\n";
return ;
}
}
cout<<n<<'\n';
}
signed main() {
cin.tie(0); ios::sync_with_stdio(false);
int T; cin>>T; while(T--) sol();
return 0;
}