2480: Spoj3105 Mod

Description

已知数a,p,b,求满足a^x≡b(mod p)的最小自然数x。
 

Input

     每个测试文件中最多包含100组测试数据。
     每组数据中,每行包含3个正整数a,p,b。
     当a=p=b=0时,表示测试数据读入完全。
 

Output

 
     对于每组数据,输出一行。
     如果无解,输出“No Solution”(不含引号),否则输出最小自然数解。
 

Sample Input

5 58 33
2 4 3
0 0 0

Sample Output

9
No Solution

HINT

  100%的数据,a,p,b≤1e9。


扩展bsgs

这题没规定p是质数,逆元就得用扩欧来做...

首先如果如果存在解x且gcd(a,p) != 1

那么把化为

把式子写成

令d = gcd(a,p)有


一直处理到gcd(a,p)为1,并且如果b不能整除d 即无解

此时得到


此时有 

此时用一般的bsgs 处理,


考虑令 


此时式子可化为



那么显然当时最优。

用map记录一下

然后枚举t即可...注意p不一定为质数

的值需用exgcd处理

累死我了...

c++代码如下:

#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i = x; i <= y ;++ i)
#define repd(i,x,y) for(register int i = x; i >= y ; --i)
using namespace std;
typedef long long ll;
template<typename T>inline void read(T&x)
{
    x = 0;char c;int sign = 1;
    do { c = getchar(); if(c == '-') sign = -1; }while(!isdigit(c));
    do { x = x * 10 + c - '0'; c = getchar(); }while(isdigit(c));
    x *= sign;
}
 
int a,p,b;
map<int,int>mp;
 
int gcd(int x,int y) { return !y ? x : gcd(y,x%y);}
 
int quick_pow(int x,int y,int p)
{
    int ans = 1;
    while(y)
    {
        if(y&1) ans = (ll)ans * x %p;
        x = (ll)x * x % p;
        y >>= 1;
    }
    return ans;
}
 
int ex_gcd(int a,int b,int&x,int&y)
{
    if(!b) { x = 1; y = 0; return a; }
    ex_gcd(b,a%b,y,x);
    y -= a/b*x;
}
 
inline void ex_bsgs(int a,int p,int b)
{
    a %= p;b %= p; 
    if(b == 1) return void(puts("0"));
    int x,d,e = 1,cnt = 0;
    while((d = gcd(a,p)) != 1)
    {
        if(b % d) return void(puts("No Solution"));
        b /= d;p /= d;e = (ll)e * a/d%p;cnt++;
        if(e == b) { return void(printf("%d\n",cnt)); }
         
    }
    int t = ceil((double)sqrt(p)),k;
    ex_gcd(quick_pow(a,t,p),p,k,x);
    k = (k%p+p)%p;
    mp.clear();mp[e] = 0;
    x = e;
    rep(i,1,t - 1)
    {
        x = (ll)x * a % p;
        if( !mp.count(x) ) mp[x] = i;
    }
 
    rep(i,0,t - 1)
    {
        if(mp.count(b)) return void(printf("%d\n",mp[b] + i*t + cnt));
        b = (ll)b * k % p;
    }
     
    puts("No Solution");
}
 
int main()
{
    while(1)
    {
        read(a);read(p);read(b);
        if(!a && !p && !b) break;
        if(p == 1) { puts("0");continue; }
        ex_bsgs(a,p,b);
    }
    return 0;
}

补一份spoj:ac代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<iostream>
#include<cctype>
#include<algorithm>
#define rep(i,x,y) for(register int i = x; i <= y ;++ i)
#define repd(i,x,y) for(register int i = x; i >= y ; --i)
using namespace std;
typedef long long ll;
template<typename T>inline void read(T&x)
{
    x = 0;char c;int sign = 1;
    do { c = getchar(); if(c == '-') sign = -1; }while(!isdigit(c));
    do { x = x * 10 + c - '0'; c = getchar(); }while(isdigit(c));
    x *= sign;
}
 
int a,p,b;
 
int gcd(int x,int y) { return !y ? x : gcd(y,x%y);}
 
int quick_pow(int x,int y,int p)
{
    int ans = 1;
    while(y)
    {
        if(y&1) ans = (ll)ans * x %p;
        x = (ll)x * x % p;
        y >>= 1;
    }
    return ans;
}
 
int ex_gcd(int a,int b,int&x,int&y)
{
    if(!b) { x = 1; y = 0; return a; }
    ex_gcd(b,a%b,y,x);
    y -= a/b*x;
}
 
const int P = 999979,N = 1e5 + 50;
int head[1000000],z[N],tot;
int to[1000000],w[1000000],nxt[1000000],Tot;
inline void add(int x,int y,int val)
{
	nxt[Tot] = head[x];
	w[Tot] = val;
	to[Tot] = y;
	head[x] = Tot++;	
}

inline int get(int x)
{
	x = 1ll * x * 233 % P;
	return x;
}

inline int check(int x)
{
	int ans = -1;
	int y = get(x);
	for(register int i = head[y];~i;i=nxt[i])
		if(to[i] == x)
		{
			if(ans == -1) ans = w[i];
			else ans = min(ans,w[i]);
		}
	return ans;	
}

inline void ex_bsgs(int a,int p,int b)
{
    a %= p;b %= p; 
    if(b == 1) return void(puts("0"));
    int x,d,e = 1,cnt = 0;
    while((d = gcd(a,p)) != 1)
    {
        if(b % d) return void(puts("no solution"));
        b /= d;p /= d;e = (ll)e * a/d%p;cnt++;
        if(e == b) { return void(printf("%d\n",cnt)); }
         
    }
    int t = ceil((double)sqrt(p)),k;
    ex_gcd(quick_pow(a,t,p),p,k,x);
    k = (k%p+p)%p;
    x = e;
	
	int u = get(e);
	add(u,e,0);z[++tot] = u;

    rep(i,1,t - 1)
    {
        x = (ll)x * a % p;
		int y = get(x);
        add(y,x,i); z[++tot] = y;
    }
 
    rep(i,0,t - 1)
    {
		int z;
        if((z = check(b)) != -1) return void(printf("%d\n",z + i*t + cnt));
        b = (ll)b * k % p;
    }
     
    puts("no solution");
}
 
int main()
{
	memset(head,-1,sizeof head);
    while(scanf("%d%d%d",&p,&a,&b) != EOF)
    {
        if(p == 1) { puts("0");continue; }
        ex_bsgs(a,p,b);
		rep(i,1,tot) head[z[i]] = -1; tot = 0;Tot = 0;
    }
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值