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;
}

浙公网安备 33010602011771号