[数论]JZOJ 5946 时空幻境
分析
显然要求出循环节,然后我们列一下式子:
p=998244353
xkA≡x(mod p)
因为p是素数,所以可以两边乘上x的逆元,得
kA≡1(mod p)
然后我们只要求A这个原根即可,然后我们知道原根在1~p-1之间,然后p-1是998244352,可以仔细研究一下这个数,发现它可以拆成:7*17*223
然后这个因数才96个,暴力枚举因数,如果达到要求就退出,然后分类讨论:
当原根为奇数时,是个环,答案为n-min(m,ord-1)
当原根为偶数时,是1/2倍的断开的边,答案为n-min(m,ord/2)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; typedef long long ll; const int P=998244353; int t,n,m,x,k,yz[210],cnt; ll Pow(ll x,int y) { ll ans=1; while (y) { if (y&1) ans=ans*x%P; x=x*x%P; y>>=1; } return ans; } int main() { freopen("braid.in","r",stdin); freopen("braid.out","w",stdout); scanf("%d",&t); for (int i=1;i*i<=P-1;i++) if ((P-1)%i==0) yz[++cnt]=i,yz[++cnt]=(P-1)/i; sort(yz+1,yz+cnt+1); while (t--) { int ans=2147483647; scanf("%d%d",&n,&m); scanf("%d%d",&x,&k); if (k==1||x==0) printf("%d\n",n); else if (x==n||k==n||k==0) printf("%d\n",n-1); else { for (int i=1;i<=cnt;i++) if (Pow(k,yz[i])==1) { ans=yz[i]; break; } printf("%d\n",n-(ans&1?min(m,ans-1):min(m,ans/2))); } } }
在日渐沉没的世界里,我发现了你。