Bzoj 2242: [SDOI2011]计算器(BSGS)

    xiaoxiao2021-03-26  37

    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 HINT Source 第一轮day1

    /* 复合题hhh. 前两问裸的快速幂 exgcd. 读入int64 不要图快用scanf linux好像不行? 然后这题case 3 是BSGS. 由于本人比较弱 所以我只能感性的认识一下BSGS. y^x≡z(mod p). 这题暴力的话复杂度是O(p)的. 因为根据费马小定理y^(p-1)≡1(mod p). 剩余系元素的个数就是p-1,再往后就出现循环了. 然后我们采用分块的思想,令m=√p. 然后就有y^(km+i)≡z(mod p). y^i≡ine(y^km)*z(mod p) (ine x为x的逆元). 然后左边hash存表,右边枚举k. 逆元是积性函数. 右边就变成了ine(y^m(k-x))*[ine(y^m)]^x. 枚举k即可. 然后因为费马小定理有y^m*y^(p-m-1)≡1(mod p). so ine(y^m)=y^(p-m-1). 复杂度就变成了O(sqrt(p)). */ #include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<map> #define LL long long using namespace std; int k,t,n,p; LL a,b,x,y,c; map<int ,int >s; LL mi() { LL tot=1; while(b) { if(b&1) tot=tot*a%p; a=a*a%p; b>>=1; } return tot%p; } void slove1() { while(t--) { cin>>a>>b>>p;// 1 W. //scanf("%lld%lld%lld",&a,&b,&p); printf("%lld\n",mi()); } } void exgcd(LL a,LL b,LL &x,LL &y) { if(!b) {x=1,y=0;return;} else exgcd(b,a%b,y,x),y-=(a/b)*x; } void slove2() { while(t--) { cin>>a>>c>>b; LL g=__gcd(a,b); if(c%g) printf("Orz, I cannot find x!\n"); else { x=y=0; exgcd(a,b,x,y); x*=c;g=b/g; x=(x%g+g)%g; cout<<x<<endl; } } } LL mi1(LL aa,LL bb,LL pp) { LL tot=1; while(bb) { if(bb&1) tot=tot*aa%pp; aa=aa*aa%pp; bb>>=1; } return tot%pp; } map<int,int> mp; void slove3() { int ans=0,y,z; bool flag=false; while(t--) { scanf("%d%d%d",&y,&z,&p);y%=p; if (!y&&!z) {printf("1\n");continue;} if (!y){printf("Orz, I cannot find x!\n");continue;} s.clear(); LL m=ceil(sqrt(p)),tot=1;s[1]=m+1; for(int i=1;i<=m-1;i++) { tot=tot*y%p; if(!s[tot]) s[tot]=i; } bool flag=false; LL tmp=mi1(y,p-1-m,p),ni=1;//2 W. for(int k=0;k<=m-1;k++) { int i=s[z*ni%p]; if(i) { if(i==m+1) i=0; flag=true;printf("%d\n",k*m+i);break; } ni=ni*tmp%p; } if(!flag) printf("Orz, I cannot find x!\n"); } return ; } int main() { scanf("%d%d",&t,&k); if(k==1) slove1(); else if(k==2) slove2(); else slove3(); return 0; }
    转载请注明原文地址: https://ju.6miu.com/read-663012.html

    最新回复(0)