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。
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
2
1
2
【样例输出2】
2
1
0
这道题就是一道板子合集。
发现B站样例没有操作3,那么这就很难受。
但是洛谷和codevs上面有。
对于操作1,NOIP提高组D1T1难度。
对于操作2,因为有 XY≡Z,由数论姿势可以得到
X*Y*Y-1≡X≡Z*Y-1(mod p);
Y-1是指Y的逆元。因为题目说了P为素数,用欧拉定理就可以了。
对于操作3,离散数对离散对数板子题。
这一类做法就是套路分块。
设x=i*m+j。则有:
Y(i*m+j)≡Z;
即 Yi*m≡Z*Y-j;
枚举i,则Yi*m可以算出来。假设为K。
于是就有:
Z*Y-j≡K (mod p)
然后像第二问一样把Y-j求出来,看一下[0,m)内有没有解。
这个东西可以用一个哈希表或者map,set什么的预处理[0,m)的逆元来搞搞。
所以说m选在√n的时候是最优秀的。
然后因为某很懒,不愿意想太多事,所以把这个算法懒化了一下。
(这么干的某不是第一个。)
设x=i*m-j;
没错最后的式子就是
Z*Yj≡K (mod p);
一个小小的改动,就可以不用找逆元了。
最后提一下判断无解的点:
对于操作2,如果Y=0而Z!=0就一定无解。
对于操作3,如果Y=0而Z!=0就一定无解。
对于操作3,找到最后找不到了就是无解了。
然后我就想知道B站那些时间只要三位数的老爷是什么情况。
可能操作2用exgcd更优秀吧,真的吗?
某的3000ms完全没戏啊,应该是卡不下来的?
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <cstring>
#include <queue>
#include <complex>
#include <stack>
#include <cmath>
#define LL long long int
#define dob double
using namespace std;
const int N = 1000010;
struct Node{int to,val,next;}E[N];
int n,type,head[N],tot;
int gi()
{
int x=0,res=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*res;
}
inline int QPow(int d,int z,int Mod){
int ans=1;
for(;z;z>>=1,d=1ll*d*d%Mod)
if(z&1)ans=1ll*ans*d%Mod;
return (ans+Mod)%Mod;
}
inline void link(int u,int v,int w){
E[++tot]=(Node){v,w,head[u]};
head[u]=tot;
}
inline void work1(){
while(n--){
int y=gi(),z=gi(),p=gi();
printf("%d\n",QPow(y%p,z%(p-1),p));
}
return;
}
inline void work2(){
while(n--){
int y=gi(),z=gi(),p=gi();
y%=p;z%=p;
if(!y && z){
printf("Orz, I cannot find x!\n");
continue;
}
int x=QPow(y,p-2,p);
x=1ll*x*z%p;
printf("%d\n",x);
}
return;
}
inline void work3(){
while(n--){
int y=gi(),z=gi(),p=gi();
y%=p;z%=p;
if(!y && z){
printf("Orz, I cannot find x!\n");
continue;
}
int m=sqrt(p),flag=0;
memset(head,0,sizeof(head));tot=0;
for(int i=0,d=1;i<m;++i){
link(d%N,d,i);
d=1ll*d*y%p;
}
for(int i=1;i<=m && !flag;++i){
int ny=QPow(y,i*m,p);
int x=QPow(z,p-2,p);
x=1ll*x*ny%p;
for(int e=head[x%N];e;e=E[e].next)
if(E[e].to==x){
printf("%d\n",(i*m-E[e].val)%p);
flag=1;break;
}
}
if(!flag)
printf("Orz, I cannot find x!\n");
}
}
int main()
{
n=gi();type=gi();
if(type==1)work1();
if(type==2)work2();
if(type==3)work3();
/*fclose(stdin);
fclose(stdout);*/
return 0;
}