【Bzoj】3122: [Sdoi2013]——随机数生成器(大步小步算法)
Time Limit: 10 Sec | Memory Limit: 256 MB |
---|
Description
Input
输入含有多组数据,第一行一个正整数T,表示这个测试点内的数据组数。
接下来T行,每行有五个整数p,a,b,X1,t,表示一组数据。保证X1和t都是合法的页码。
注意:P一定为质数
Output
共T行,每行一个整数表示他最早读到第t页是哪一天。如果他永远不会读到第t页,输出-1。
Sample Input
3
7 1 1 3 3
7 2 2 2 0
7 2 2 2 1
Sample Output
1
3
-1
HINT
0<=a<=P-1,0<=b<=P-1,2<=P<=10^9
中文题意,就不解释了。对于公式
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <string>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <algorithm>
#define rr() freopen("in.in","r",stdin)
#define ww() freopen("out.out","w",stdout)
using namespace std;
typedef long long LL;
LL a,b,p,x1,t;
void exgcd(LL A,LL B,LL &g,LL &x,LL &y){//扩展欧几里得
if(B == 0){
g = A;
x = 1;
y = 0;
return ;
}
else{
exgcd(B,A%B,g,y,x);
y-=(A/B)*x;
}
}
LL INV(LL A,LL B){//求逆元
LL g,x,y;
exgcd(A,B,g,x,y);
return g==1?(x%B+B)%B:-1;
}
LL cal1(){
t = ((t-x1)%p+p)%p;
LL ans = INV(b,p);
if(ans == -1) return ans;
else return (ans*t)%p+1;
}
LL Pow(LL A, LL m){
LL ans = 1;
while(m){
if(m%2) ans = (ans*A)%p;
A = (A*A)%p;
m>>=1;
}
return ans;
}
LL bsgs(LL A, LL B,LL n){
A%=n;
if(!A){
if(!B) return 1;
else return -1;
}
LL m = (LL)sqrt(n)+1;
LL inv = INV(Pow(A,m),n);
if(inv == -1) return -1;
map<LL,LL>mp;mp.clear();
mp[1] = 0;
LL e= 1;
for(int i = 1;i<m;i++){
e = (e*A)%p;
if(!mp.count(e)) mp[e] = i;
}
for(int i =0;i<m;i++){
if(mp.count(B)) return m*i+mp[B];
B =(inv*B)%p;
}
return -1;
}
LL cal2(){
LL inv = INV(a-1,p);
x1 =(x1+b*inv)%p;
t = (t+b*inv)%p;
LL inv2 =INV(x1,p);
if(inv2 == -1) return -1;
t = (t*inv2)%p;
LL ans = bsgs(a,t,p);
return ans == -1?ans:ans+1;
}
LL solve(){
if(x1 == t) return 1;
if(a ==0) {
if(b == t) return 2;
else return -1;
}
if(a == 1) return cal1();
else return cal2();
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%lld %lld %lld %lld %lld",&p,&a,&b,&x1,&t);
printf("%lld\n",solve());
}
return 0;
}
【Bzoj】2242: [SDOI2011]——计算器
Time Limit: 10 Sec | Memory Limit: 512 MB |
---|
Description
你被要求设计一个计算器完成以下三项任务:
1、给定y,z,p,计算Y^Z Mod P 的值;
2、给定y,z,p,计算满足xy≡ Z ( mod P )的最小非负整数;
3、给定y,z,p,计算满足Y^x ≡ Z ( mod P)的最小非负整数。
Input
输入包含多组数据。
第一行包含两个正整数T,K分别表示数据组数和询问类型(对于一个测试点内的所有数据,询问类型相同)。
以下行每行包含三个正整数y,z,p,描述一个询问。
Output
对于每个询问,输出一行答案。对于询问类型2和3,如果不存在满足条件的,则输出“Orz, I cannot find x!”,注意逗号与“I”之间有一个空格。
Sample Input
【样例输入1】
3 1
2 1 3
2 2 3
2 3 3
【样例输入2】
3 2
2 1 3
2 2 3
2 3 3
【数据规模和约定】
对于100%的数据,1<=y,z,p<=10^9,为质数,1<=T<=10。
Sample Output
【样例输出1】
2
1
2
【样例输出2】
2
1
0
Source
第一轮day1
三种操作,快速幂,扩展欧几里得,离散对数。在处理原根 ax=b(modp) 的时候,要特判a = 0的情况。
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <algorithm>
using namespace std;
typedef long long LL;
LL y,z,p;
LL Pow(LL n,LL m){
n%=p;
LL ans =1 ;
while(m){
if(m&1) ans = (ans*n)%p;
n = (n*n)%p;
m>>=1;
}
return ans;
}
void exgcd(LL a,LL b,LL &g,LL &fx ,LL &fy){
if(b == 0){
g = a;
fx = 1;
fy = 0;
}
else {
exgcd(b,a%b,g,fy,fx);
fy-=fx*(a/b);
}
}
LL Inv()
{
LL g,fx,fy;
exgcd(y,p,g,fx,fy);
if(z%g) return -1;
y/=g;z/=g;p/=g;
return ((fx*z)%p+p)%p;
}
LL bsgs(LL a,LL b, LL n){
a%=n;
if(!a && !b) return 1;
if(!a) return -1;
LL m = (LL)sqrt(n)+1;
LL inv = Pow(Pow(a,m),n-2);
map<LL,LL>mp; mp.clear();
mp[1] = 0;
LL st = 1;
for(int i =1;i<m;i++){
st=(st*a)%p;
if(!mp.count(st)) mp[st] = i;
}
for(int i = 0;i<m;i++){
if(mp.count(b)) return i*m+mp[b];
b = (b*inv)%p;
}
return -1;
}
int main(){
int T,k;
while(~scanf("%d %d",&T,&k)){
while(T--){
scanf("%lld %lld %lld",&y,&z,&p);
if(k == 1) printf("%lld\n",Pow(y,z));
else if(k == 2){
LL ans = Inv();
if(ans == -1) printf("Orz, I cannot find x!\n");
else printf("%lld\n",ans);
}
else{
LL ans = bsgs(y,z,p);
if(ans == -1) printf("Orz, I cannot find x!\n");
else printf("%lld\n",ans);
}
}
}
return 0;
}