Description
Tim拥有控制时间的能力。他学会了BFS后,出了一道题:求出一张无向图中连通块的个数。他想请你做出这道题来
Input
![](https://i-blog.csdnimg.cn/blog_migrate/55e6261fd3482481099db2c190e629bb.png)
![](https://i-blog.csdnimg.cn/blog_migrate/feebc8e4e581fc0c6f0cfff0e3d7fc17.png)
Output
T行,每行一个数,表示联通块的个数。
Sample Input
Sample Input1 1 998244353 4 1 3 Sample Input2 5 998244353 9088 709393585 591328017 998244353 8408 476368048 122172238 998244353 217 922587543 10 998244353 2948991 40846641 7 998244353 2692315 542601916 5
Sample Output
Sample Output2 998244349 样例解释 边为{1,3},{9,27},{81,243},{729,2187} ,所以共有998244349个联通块。 Sample Output2 998235265 998235945 998244136 995295362 995552038
Data Constraint
对所有数据,n=998244353, 1<=m,k,x<998244353, 1<=T<=10000
![](https://i-blog.csdnimg.cn/blog_migrate/5ea43ba3217eeacf3784164d5d6b8ed4.png)
分析
显然要求出循环节,然后我们列一下式子:
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://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.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))); } } }