BZOJ2242 SDOI2011 计算器calc
第一类询问:直接快速幂不会的右转百度
第二类询问:求个逆元再判一下不会的右转百度
第三类询问:
首先有费马小定理、、所以答案不会超过p、、
但是p的范围还是要T、、
于是想到二分或者分块、、、
二分的话感觉没什么前途、、
于是分块、、
(我不会打同余标记就用等于代替了、、)
设最终答案x=k[sqrt(p)]+i
那么有
y^x=z(mod p)
y^(k[sqrt(p)]+i)=z(mod p)
y^i=z/(y^k[sqrt(p)]) (mod p)
y^i=z*y^(k[sqrt(p)](p-2)) (mod p) (费马小定理)
这里i的范围是0-[sqrt(p)]-1的、、k的范围是0..P/[sqrt(p)]的、、
然后我们可以预处理出y^i存在hash表或者map里、、
然后枚举k看是否存在这样一个i、、
于是就可以解决了、、详细的可以见code、、
Code:
#include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <cmath> #include <cstring> #include <vector> #include <set> #include <map> #include <queue> #define ps system("pause") #define message printf("*\n") #define pb push_back #define X first #define Y second #define PII pair<int,int> #define rep(a,b,c) for(int a=b;a<=c;a++) #define per(a,b,c) for(int a=b;a>=c;a--) typedef long long ll; using namespace std; int T,k; ll y,z,p,te,ans,c; map<ll,ll> app; int main(){ cin >>T >>k; while (T--){ cin >>y >>z >>p; app.clear(); switch (k){ case 1: te=y;ans=1; while (z){ if (z&1) ans=ans*te%p; (te*=te)%=p;z/=2; } cout <<ans <<endl; break; case 2: c=p-2;te=y;ans=1; while (c){ if (c&1) ans=ans*te%p; (te*=te)%=p;c/=2; } ans=z*ans%p; if ((ans*y%p)==(z%p)) cout <<ans <<endl; else puts("Orz, I cannot find x!"); break; case 3: if (y%p==0){ puts("Orz, I cannot find x!"); break; } te=1; rep(i,0,int(sqrt(p))){ app[te]=i+1; te=te*y%p; } te=int(sqrt(p)); bool fd=false; rep(k,0,p/te){ c=k*(p-2)*te; ll cur=y,res=1; while (c){ if (c&1) res=res*cur%p; (cur*=cur)%=p;c/=2; } res=res*z%p; if (app[res]){ fd=true; cout <<k*te+app[res]-1 <<endl; break; } } if (!fd) puts("Orz, I cannot find x!"); break; } } return 0; }