[数论]JZOJ 5946 时空幻境

Description

Tim拥有控制时间的能力。他学会了BFS后,出了一道题:求出一张无向图中连通块的个数。他想请你做出这道题来
 
 

Input


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

分析

显然要求出循环节,然后我们列一下式子:

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)

 

#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)));
        }
    }
}
View Code

 

posted @ 2018-11-04 19:09  Vagari  阅读(189)  评论(0编辑  收藏  举报