bzoj 1420: Discrete Root BSGS+原根

Description

已知k,a,p,求x ^ k=a (mod p)的所有根(根的范围[0,p-1]

Input

三个整数p,k,a。0 < = a < p < = 10^9, 2 < = k < = 100000

Output

第一行一个整数,表示符合条件的x的个数。
第二行开始每行一个数,表示符合条件的x,按从小到大的顺序输出。
Sample Input

11 3 8
Sample Output

1

2

分析:一道原根的水题。首先,根据原根的性质,每一个1<=x<=phi(n)的数都能用g^i来表示(其中g表示一个原根)。也就是说,原式=x^A=(g^i)^A=(g^A)^i。其中g^A是已知的,也就是一个BSGS的版子了,求出所有i后,g^i就是所有的解,然后排序即可。

代码:

扫描二维码关注公众号,回复: 890274 查看本文章
/**************************************************************
    Problem: 1420
    User: beginend
    Language: C++
    Result: Accepted
    Time:296 ms
    Memory:16952 kb
****************************************************************/

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#define LL long long

const int maxn=1500;
const int c=1e6+7;

using namespace std;

LL cnt;
LL p[maxn],ans[maxn];
LL n,a,b,g,k;

struct node{
    LL x,y;
}hash[c];

void divide(LL x)
{
    for (LL i=2;i<=trunc(sqrt(x));i++)
    {
        if (x%i==0)
        {
            p[++cnt]=i;
            while (x%i==0) x/=i;
        }
    }
    if (x>1) p[++cnt]=x;
}

LL pow(LL x,LL y)
{
    if (y==0) return 1;
    if (y==1) return x;
    long long d=pow(x,y/2);
    d=(d*d)%n;
    if (y%2==1) d=(d*x)%n;
    return d;
}

void find_root(LL x)
{
    LL flag;
    for (LL i=1;i<x;i++)
    {
        flag=0;
        for (LL j=1;j<=cnt;j++)
        {
            if (pow(i,(x-1)/p[j])==1)
            {
                flag=1;
                break;
            }
        }
        if (!flag)
        {
            g=i;
            return;
        }
    }
}

void find(LL x,LL s)
{
    LL t=x%c;
    while (hash[t].x!=0)
    {
        if (hash[t].x==x) 
        {
            if (s-hash[t].y<=n-1) ans[++k]=s-hash[t].y;
        }
        t=(t+1)%c;
    }
}

void insert(LL x,LL y)
{
    LL t=x%c;
    while (hash[t].x!=0) t=(t+1)%c;
    hash[t].x=x;
    hash[t].y=y;
}

void BSGS(LL a,LL b)
{
    //if (b==1) ans[++k]=0;
    LL x=1;
    LL block=trunc(sqrt(n))+1;
    for (LL i=0;i<block;i++)
    {
        insert((x*b)%n,i);
        x=(x*a)%n;
    }
    LL y=x,i;
    for (LL i=1;i<block;i++)
    {
        if (i*block>=n) break;
        find(y,i*block);
        y=(y*x)%n;
    }
}

int main()
{
     scanf("%lld%lld%lld",&n,&a,&b);
     divide(n-1);  
     find_root(n);
     BSGS(pow(g,a),b);

     for (LL i=1;i<=k;i++) ans[i]=pow(g,ans[i]);
     sort(ans+1,ans+k+1);
     printf("%lld\n",k);
     for (LL i=1;i<=k;i++) printf("%lld\n",ans[i]);
}

猜你喜欢

转载自blog.csdn.net/liangzihao1/article/details/79933336