P5582 【SWTR-01】Escape

b 为可用步数序列,长度为 m

考虑必要性,即每个点都能通过 b 的线性组合在模 n 意义下表示出来。

b1x1+b2x2+...+bmxm+nxm+1 能表示出来 [0,n) 中的每个数,这一部分根据裴蜀定理可得。

这个条件可能是充要的,考虑证明。

定理 31.20:
对于任意正整数 an,若 d=gcd(a,n),则在 Zn 中,<a>=<d>

引理
环大小为 n,若初始在位置 p,每次跳 k 步,k|n,则到达的位置一定是 xp(modk)
证明:考虑原先到达的位置 x0(modk),初始位置在 p 可看做初始位置在 0,跳完后再向右跳一次 p 步,因为跳 k 步能取遍且互不相同的位置 x[0,n),k|x,所以你再向右跳显然也能取遍,且互不相同。

考虑先跳 b1,即记 d=gcd(b1,n),跳完了,d,2d ... (n/d1)d,0,那么考虑只要每次跳完这样的一个循环,能够位移到组内另一个地方即可。这样每一次跳到的都是不一样的。

即问题变成了 b2,b3 ... bm 跳完 [0,d),考虑结构一样,如此操作下去,最终变成 bm 跳完 [0,gcd(n,b1,b2 ... bm1)),显然在 Zgcd(n,b1,b2 ... bm1) 中,|<bm>|=gcd(n,b1,b2 ... bm1),因此可以跳完。然后子问题可以完成,则上级问题推回去也可以完成。

#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; }

__EOF__

本文作者F x o r G
本文链接https://www.cnblogs.com/xugangfan/p/17040634.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   FxorG  阅读(29)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示