http://www.lydsy.com/JudgeOnline/problem.php?id=3122
看了一眼,以为是脑残题,可以先找出一个循环,然后再搞搞,发现找出循环代价太大,或者说有可能有些数多次出现了,但并没有循环。
然后推公式吧:(卧槽,就几个月没碰数列就tm不会做了~ 然后搞出一个通项)
xn= a^(n-1) x1 +b* (a^(n-1)-1)/(a-1) 答案就是求使得xn=t mod p中n最小的值。
然后exgcd解方程,把最小的a^(n-1)解x(其实是在mod p的情况下)出来了,然后怎么办? 我以为一定是x能够整除以a,然后YY了一个类似于背包二进制优化的方法来做,直到对排出错误才发现不对。
暴力枚举?不可行! 暴力枚举复杂度又变回去,相当于解方程还浪费了时间。
然后没办法,到处搜题解,直到看到一个叫BSGS的东东。
简单介绍一下BSGS:
就是解a^x = b mod p 已知a,b,p求解x的算法。
参考:http://www.cnblogs.com/yuiffy/p/3877381.html
参考2(详细):http://blog.youkuaiyun.com/clove_unique/article/details/50740412
然后貌似这样能够找到最小的x.(我也不是很懂QAQ,貌似因为hash的时候存的是最小的j,同时i也是从最小的开始枚举,这样貌似x就是最小的了~~~~)
然后还有一个坑点:
我hash[1]=0对吧,但是枚举i计算b*a^(-m*i)的时候就发现找不到了(明明出现过),肿么办? 网上有人利用了hash.count看这个位置是否被赋过值.
也有hash[1]=m+1(hash值一定小于m的,因为最多枚举到m-1,然后找到了再变成0)。
这两种都可行,但貌似用count的更快- -(不懂QAQ)。
最后,orz各种10组数据跑进250ms的超级神犇&&超级大神,orz各种跑进1s的大神,orzYY出各种解法的大神。
蒟蒻贴码:
(PS:跑得很慢- - |||| 跑了2s度,被甩了10倍)
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<cmath>
#include<iostream>
#include<map>
#define ll long long
using namespace std;
/*
真是弱爆了,连数列都不会做了。
推到: xn= a^(n-1) x1 +b* (a^(n-1)-1)/(a-1)
c=ni(a-1)
t=a^(n-1)(bc+x1)-bc mod p
令 x=a^(n-1) A=bc+x1 t+bc=B
B=Ax mod p
*/
ll p,a,b,x1,t;
ll A,B;
map<ll,int >hash;
ll qk(ll x,ll y)
{
ll res=1;
while(y)
{
if(y&1)res=(res*(x%p))%p;
y>>=1;
x=(x*x)%p;
}
return res;
}
ll exgcd(ll a,ll b,ll &x,ll &y)//ax+by=gcd(a,b)
{
if(b==0)
{
x=1;
y=0;
return a;
}
ll d=exgcd(b,a%b,x,y);
//
ll t=x;
x=y;
y=t-a/b*y;
return d;
}
void work(ll x)//BSGS
{
//求解 a^n = x mod p
//
hash.clear();
a%=p;
ll m=(ll)(sqrt(p)+0.5);
//变为a^j = x* a^(-m*i)mod p
ll t=1;
hash[1]=0;
for(int j=1;j<m;j++)
{
t=t*a%p;
if(!hash.count(t))hash[t]=j;
}
ll I=qk(qk(a,m),p-2);
ll IS=1;
for(int k=0;k<m;k++)
{
if(hash.count(IS*x%p))
{
int i=hash[IS*x%p];
printf("%lld\n",k*m+i+1);
return ;
}
IS=IS*I%p;
}
printf("-1\n");
}
void work2()
{
A=b%p;
B=(t-x1+p)%p;
//Ax+py=B
ll x,y;
ll d=exgcd(A,p,x,y);
if(B%d!=0)printf("-1\n");
else
{
x*=B/d;
x%=p;
if(x<0)x+=p;
printf("%lld\n",x+1);
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%lld%lld%lld%lld%lld",&p,&a,&b,&x1,&t);
if(x1==t)
{
printf("1\n");
continue;
}
if(a==0)
{
if(t==b)printf("2\n");
else printf("-1\n");
continue;
}
if(a==1)
{
work2();
continue;
}
ll c=qk(a-1,p-2);
A=(b*c+x1)%p;
B=(t+b*c)%p;
//求解Ax=B mod p AX+py=B 最小的x
ll x,y;
ll d=exgcd(A,p,x,y);
if(B%d!=0)printf("-1\n");
else
{
ll k=B/d;
x*=k;
y*=k;
ll u=p/d;
x=(x%u+u)%u;
//x=a^n-1
work(x);
}
}
return 0;
}