首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

Mod Tree(hdu2815高次线性同短方程)

2013-10-27 
Mod Tree(hdu2815高次线性同余方程)题意:求每个节点有K个儿子,计算最小深度D的节点数对P取模的结果是N,K^D

Mod Tree(hdu2815高次线性同余方程)

题意:求每个节点有K个儿子,计算最小深度D的节点数对P取模的结果是N,K^D = N( mod P )的最小D值 如果无解输出 Orz,I can’t find D!

思路:baby__giant算法

分两种情况

第一种 : 当A 和C互质的时候

m = sqrt(C);

A^x = A^i*m+j = B (mod C)

A^i*m*A^j = B ( mod C)

两边除以A^i*m,因为A 和C互质 所以除以A^i*m等于乘以A^i*m的逆元

什么是逆元,当A和C互质 A*b = 1 (mod C) b就是A的乘法逆元 ,所以当存在逆元 B/A = 2 (mod C) 就可以写成B*b = 2(mod C)

所以用扩展欧几里德 求出A^i*m的逆元等于A^-i*m, 化简等于

A^j = A^-i*m * B ( mod C) (0 <= j <= m)

我们可以先算出所有A^j的值存在hash中然后遍历i,计算A^i*m的逆元再乘以B mod C看它的值是否在hash中出现过,如果出现过返回i*m+j

第二种 :当A和C不互质的时候,因为不互质就没有逆元,所以我们要想办法让他们互质 计算A和C的最大公约数

因为 A^x = B (mod C) 如果d = gcd(A,C)  那么 A/d*A^x-1 = B/d ( mod C/d ) 这样一直除下去一直到A和C互质即 (A/d)^c * A^x-c = B/d^c ( mod C / d^c )

这样 A^x-c与C/d^c互质就可以求逆元了,

令k = x-c 紧接着套用上面的计算方式 将k写成  k = i*m+j

然后 (A/d)^c * A^i*m * A^j= B/d^c ( mod C / d^c ) 两边同时除以(A/d)^c * A^i*m,也就是用扩展欧几里德求他们的逆元等于

A^j= B/d^c* ((A/d)^c * A^i*m)^-1 *( mod C / d^c ) 这样还是先算出所有A^j存在hash中然后遍历i,计算((A/d)^c * A^i*m)^-1的逆元再乘以 B/d^c看他的值是否在hash出现过如果出现过返回 i*m+j 因为k = x - c 所以最后的k 还要+ c等于x =  i*m+j+c

如果在i的范围(0<= i <= m)都没找到合适的值或者再在化简为互质那一步B/d不能整除那就是无解

因为当解比较小的时候我们可以暴力,那么我们先计算0~~100的如果有就直接返回没有在用上述的算法


本题注意N在 (0 < = N < P) 大于P的都是无解的,还有就是当N = 0的时候就是D = 0,还有大坑就是那个无解的英文千万不能copy

A^x = B (mod p)  0 <= B < p 注意范围,看题目要求如果没有给就按照超范围无解

#include<iostream>#include<cstdio>#include<cstring>#include<vector>#include<cmath>using namespace std;typedef long long int64;struct Point{    int64 x;    int64 y;    Point (int64 x,int64 y) : x(x),y(y){}};vector<Point> v[10005];int MOD = 10000;void insert(int64 x,int64 j){    int64 k = x % MOD;    Point a(x,j);    v[k].push_back(a);}int64 Find(int64 x){    int64 k = x % MOD;    int64 temp = v[k].size();    for(int64 i = 0; i < temp; i++)    {       // printf("%I64d\n",x);        if(v[k][i].x == x)            return v[k][i].y;    }    return -1;}int64 gcd(int64 a,int64 b){    if(b == 0)        return a;    else        return gcd(b,a%b);}int64 Exgcd(int64 a,int64 b,int64&x,int64 &y){    if(b == 0)    {        x = 1,y = 0;        return a;    }    else    {        int64 r = Exgcd(b,a%b,x,y);        int64 temp = x;        x = y,y = temp - a/b*y;        return r;    }}int64 Inval(int64 a,int64 b,int64 n){    int64 x,y,d;    d = Exgcd(a,b,x,y);//printf("%I64d %I64d\n",x,y);    x = x *n % b;    x = ( x % b + b) % b;    return x;}int64 baby_gaint(int64 B,int64 N,int64 P){    int64 sum = 1%P;    for(int64 i = 0; i <= 100; i++)    {        if(sum % P == N)            return i;        sum = ( sum * B ) % P;    }    int64 cnt = 0,D = 1%P,j,tmp;   while((tmp = gcd(B,P)) != 1)    {        if(N % tmp)        {            return -1;        }        cnt++;        N = N / tmp;        P = P / tmp;        D = D * B / tmp % P;    }    int64 n = (sqrt(1.0*P));    sum = 1;    for(int64 i = 0; i < n; i++,sum = (sum * B) % P)    {        insert(sum,i);    }    int64 X;    for(int64 i = 0;; D = D * sum % P,i+= n)    {        X = Inval(D,P,N);//printf("%I64d %I64d %I64d\n",X,P,N);        if(X >= 0 && ( j = Find(X) ) != -1)        {            return i + j + cnt;        }        if(i > P) break;    }    return -1;}int main(){    int64 K,N,P;    while(scanf("%I64d%I64d%I64d",&K,&P,&N) != EOF)    {        for(int i = 0; i < 10005; i++)            v[i].clear();        int64 temp = baby_gaint(K,N,P);        if(N >= P)        {            printf("Orz,I can’t find D!\n");continue;        }        if(N == 0)        {            printf("0\n");continue;        }        if(temp == -1)            printf("Orz,I can’t find D!\n");        else            printf("%I64d\n",temp);    }    return 0;}


热点排行