bzoj3122: [Sdoi2013]随机数生成器

继前几天靠星球联盟混到400t之后靠这题神仙题混到了rk600-

……太神仙了,谁会想到柿子两边同时加一个b/(a-1)?? 这个等效替换估计出题人就是某省数竟+信竟选手 寄刀片

按这个画完柿子以后就变成 a^(n-1)=(xn+b/(a-1)) / ((x1+b*(a-1))

上BSGS

 

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<map>
using namespace std;
typedef long long LL;
LL p;
LL quick_pow(LL A,LL pp)
{
    LL ret=1;
    while(pp!=0)
    {
        if(pp%2==1)ret=(ret*A)%p;
        A=(A*A)%p;pp/=2;
    }
    return ret;
}

LL getinv(LL A){return quick_pow(A,p-2);}
LL getB(LL a,LL b,LL x1,LL xn){return ((xn+b*getinv(a-1)%p)%p) * getinv((x1+b*getinv(a-1)%p)%p) %p;}

map<LL,LL>Hash;
LL BSGS(LL a,LL b)
{
    Hash.clear();
    a%=p;b%=p;
    if(a==0)return (b==0)?1:-2;
    
    LL t=(LL(sqrt(double(p+1))))+1,k=1;
    for(int j=0;j<t;j++)
    {
        Hash[b*k%p]=j;//b*a^j
        k=(k*a)%p;
    }
    
    a=quick_pow(a,t);//a^t
    k=a;
    for(int i=1;i<=t;i++)
    {
        if(Hash.find(k)!=Hash.end())
        {
            LL j=Hash[k];
            if(t*i-j>=0)return t*i-j;
        }
        k=(k*a)%p;
    }
    return -2;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        LL a,b,x1,xn;
        scanf("%lld%lld%lld%lld%lld",&p,&a,&b,&x1,&xn);
        if(x1==xn){printf("1\n");continue;}
        if(a==0)
        {
            if(xn==b)printf("2\n");
            else printf("-1\n");
            continue;
        }
        if(a==1) 
        {
            if(b==0)
            {
                if(xn==x1)printf("1\n");
                else printf("-1\n");
            }
            else printf("%d\n",((xn-x1+p)%p)*getinv(b)%p+1);
            continue;
        }
        printf("%lld\n",BSGS(a,getB(a,b,x1,xn))+1);
    }
    return 0;
}

 

posted @ 2018-09-20 11:03  AKCqhzdy  阅读(164)  评论(1编辑  收藏  举报