BZOJ 3122 [Sdoi2013]随机数生成器 BSGS

题意:链接

方法: BSGS

解析:

首先他给出了你数列在mod p意义下的递推式。

所以我们可以求出来通项。

Xn+1+k=a?(Xn+k)

所以b=(a?1)?k

则我们可以解出来k

那么这个数列的通项是什么呢?

Xn=an?1?(X1+k)?k

题中给定Xn

求出n就行了。

所以只需要移项就好了。

这里有个问题,此时我们的通项公式是不包含首项的,所以需要特判首项,另外还有第一项以外为常数项的时候。

代码:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mod 140345
using namespace std;
typedef long long ll;
int T,cnt;
int head[mod+10];
ll ans;
struct node
{
    ll from,to,val;
    int next;
}edge[mod+10];
void init()
{
    memset(head,-1,sizeof(head));
    cnt=1;
}
void edgeadd(ll from,ll to,ll val)
{
    edge[cnt].from=from,edge[cnt].to=to,edge[cnt].val=val;
    edge[cnt].next=head[from];
    head[from]=cnt++;
}
void exgcd(ll a,ll b,ll &x,ll &y,ll &gcd)
{
    if(!b)
    {
        x=1,y=0,gcd=a;
        return;
    }
    exgcd(b,a%b,y,x,gcd);
    y=y-a/b*x;
}
ll get_inv(ll x,ll MOD)
{
    ll X,Y,GCD;
    exgcd(x,MOD,X,Y,GCD);
    return (X%MOD+MOD)%MOD;
}
void BSGS(ll A,ll B,ll C)
{
    init();
    ll m=(int)ceil(sqrt(C));
    ll k=1;
    for(int i=0;i<m;i++)
    {
        int flag=1;
        for(int j=head[k%mod];j!=-1;j=edge[j].next)
        {
            if(edge[j].val==k){flag=0;break;}
        }
        if(flag)edgeadd(k%mod,i,k);
        k=k*A%C;
    }
    ll invk=get_inv(k,C);
    ll invD=1;
    for(int i=0;i<=m;i++)
    {
        ll tmpB=B*invD%C;
        for(int j=head[tmpB%mod];j!=-1;j=edge[j].next)
        {
            if(edge[j].val==tmpB){ans=edge[j].to+i*m;return;}
        }
        invD=invD*invk%C;
    }
}
ll p,a,b,x1,t;
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld%lld%lld%lld%lld",&p,&a,&b,&x1,&t);
        if(x1==t){puts("1");continue;}
        if(a==0)
        {
            if(x1==t)puts("1");
            else if(b==t)puts("2");
            else puts("-1");
        }else if(a==1)
        {
            t=((t-x1)%p+p)%p;
            ll X,Y,GCD;
            exgcd(b,p,X,Y,GCD);
            if(t%GCD!=0)puts("-1");
            else printf("%lld\n",((X*t/GCD)%(p/GCD)+(p/GCD))%(p/GCD)+1);
        }else
        {
            ll k=b*get_inv(a-1,p)%p;
            t=(t+k)%p*get_inv(x1+k,p)%p;
            ans=-1;
            BSGS(a,t,p);
            if(ans!=-1)printf("%lld\n",ans+1);
            else puts("-1");
        }
    }
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-09-30 18:56:12

BZOJ 3122 [Sdoi2013]随机数生成器 BSGS的相关文章

BZOJ 3122 SDOI2013 随机数生成器

一大堆边界一开始并不知道,胡乱判了几个之后一直WA 无奈之下只好去下载了数据,然后就疯狂判各种奇怪的边界了 刨去边界问题 首先我们考虑a=1的情况 x1+k*b=t(mod p) ex_gcd即可解 考虑a>1的情况 令S=X+b/(a-1) 原式就变成了一个等比数列 即S1*a^k=(t+b/(a-1))(mod p) 移项之后BSGS解即可 其他边界都可以O(1)判断 #include<cstdio> #include<cstring> #include<iostr

BZOJ 3122 SDOI2013 随机数生成器 数论 EXBSGS

题目大意:给定一个数列X(i+1)=(a*Xi+b)%p 求最小的i>0,使Xi=t 0.0 此题能1A真是太好了 首先讨论特殊情况 若X1=t ans=1 若a=0 ans=b==t?2:-1 若a=1 X1+b*(ans-1)==t (%p) 扩展欧几里得 令 temp=b/(a-1) 则有 (X(i+1)+temp)=a*(Xi+temp) Xans=(X1+temp)*a^(ans-1)-temp 其中Xans%p=t 则有 (X1+temp)*a^(ans-1)-temp == t (

【BZOJ 3122】 [Sdoi2013]随机数生成器 (BSGS)

3122: [Sdoi2013]随机数生成器 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1442  Solved: 552 Description Input 输入含有多组数据,第一行一个正整数T,表示这个测试点内的数据组数. 接下来T行,每行有五个整数p,a,b,X1,t,表示一组数据.保证X1和t都是合法的页码. 注意:P一定为质数 Output 共T行,每行一个整数表示他最早读到第t页是哪一天.如果他永远不会读到第t页,输出-1. Sa

【BZOJ-3122】随机数生成器 BSGS

3122: [Sdoi2013]随机数生成器 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1362  Solved: 531[Submit][Status][Discuss] Description Input 输入含有多组数据,第一行一个正整数T,表示这个测试点内的数据组数. 接下来T行,每行有五个整数p,a,b,X1,t,表示一组数据.保证X1和t都是合法的页码. 注意:P一定为质数 Output 共T行,每行一个整数表示他最早读到第t页是

bzoj3122: [Sdoi2013]随机数生成器

3122: [Sdoi2013]随机数生成器 Description Input Output HINT $ 0 \leqslant a \leqslant P-1,0 \leqslant b \leqslant P-1,2 \leqslant P \leqslant 10^9 $ BSGS裸题 把线性递推式转化为通项公式为 $ x[n] = x1 * A^{n-1} + \frac {B*A^{n-1}} {A-1} = t $ 移项,得: $ (x1 + \frac {B} {A-1}) *

【bzoj3122】: [Sdoi2013]随机数生成器 数论-BSGS

[bzoj3122]: [Sdoi2013]随机数生成器 当a>=2 化简得 然后 BSGS 求解 其他的特判 : 当 x=t  n=1 当 a=1  当 a=0 判断b==t 1 /* http://www.cnblogs.com/karl07/ */ 2 #include <cstdlib> 3 #include <cstdio> 4 #include <cstring> 5 #include <cmath> 6 #include <map&

BZOJ 2875: [Noi2012]随机数生成器( 矩阵快速幂 )

矩阵快速幂...+快速乘就OK了 -------------------------------------------------------------------------------------- #include<bits/stdc++.h> using namespace std; typedef long long ll; ll MOD, a, c, x, n, g; ll MUL(ll a, ll b) { ll ans = 0; for(; b; b >>= 1

[Sdoi2013]随机数生成器(BSGS)

#include<map> #include<cmath> #include<cstdio> #include<iostream> #define ll long long using namespace std; inline int read(){ int x=0;char ch=getchar(); while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0'&&ch<='9'

[bzoj 2875][noi2012]随机数生成器

传送门 Description 栋栋最近迷上了随机算法,而随机数是生成随机算法的基础.栋栋准备使用线性同余法(Linear Congruential Me thod)来生成一个随机数列,这种方法需要设置四个非负整数参数m,a,c,X[0],按照下面的公式生成出一系列随机 数X[n]X[n+1]=(aX[n]+c)mod m其中mod m表示前面的数除以m的余数.从这个式子可以看出,这个序列的下一个数 总是由上一个数生成的.用这种方法生成的序列具有随机序列的性质,因此这种方法被广泛地使用,包括常用