[BZOJ2242][SDOI2011]计算器(快速幂+扩欧+BSGS)
2016-02-26 18:52
375 查看
题目描述
传送门题目描述有问题!y,z,p中只有p为质数!
题目描述有问题!y,z,p中只有p为质数!
题目描述有问题!y,z,p中只有p为质数!
重要的事情说三遍!
题解
对于操作1:快速幂而已,不存在无解的情况。
对于操作2:
扩展欧几里得算法。有解的条件为:gcd(y,p)|z
证明:
已知xy≡z(modp)
原式可化为:xy−ap=z
问题可以转化为求是否有一组数x,a使xy−ap=z
而如果把所有x,a的取值以及对应的xy−ap的得数建系的话,会发现最小的数为x,a的gcd,而其他所有的数都为gcd的倍数。
这样我们就可以得出:有解的条件为:gcd(y,p)|z
我们知道当(y,p)=1时我们可以利用扩展欧几里得求出xy−ap=gcd(y,p)即xy−ap=1的解x,a
所以将原式转换一下:
xzy+azp=1
令xz=x′,az=a′,求出x’和a’的值再与z相乘即为答案。
有人有问题吗?
能用扩展欧几里得求这个式子xzy+azp=1的解条件不是y,p互质吗?那要不要判断一下呢?
其实是不用的,因为如果满足这个式子gcd(y,p)|z的话,我们可以让等式两边同时/gcd(y,p),也就是y,z,p同时/gcd(y,p)。这样的话就保证了y,p一定互质啦。
对于操作3:
只是BSGS算法的模板啦,可以参考本博客BSGS算法学习笔记。
代码
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<map> using namespace std; #define LL long long int T,type; LL y,z,p,ans; map <LL,LL> hash; LL fast_pow(LL a,LL p,LL Mod) { LL ans=1; for (;p;p>>=1LL,a=a*a%Mod) if (p&1LL) ans=ans*a%Mod; return ans; } LL gcd(LL a,LL b) { if (!b) return a; else return gcd(b,a%b); } void exgcd(LL a,LL b,LL &x,LL &y) { if (!b) x=1,y=0; else exgcd(b,a%b,y,x),y-=a/b*x; } LL EXgcd(LL a,LL b,LL c) { LL t=gcd(a,b); if (c%t) return -1; a/=t,b/=t,c/=t; LL x=0,y=0; exgcd(a,b,x,y); x=(x%b+b)%b; if (!x) x+=b; return (x*c%b+b)%b; } LL bsgs(LL a,LL b,LL p) { if (a%p==0) return -1; hash.clear(); LL m=ceil(sqrt(p)); LL a_m=fast_pow(a,m,p); LL mul=b; for (LL j=0;j<=m;++j) { hash[mul]=j+1; mul=mul*a%p; } mul=1; for (LL i=1;i<=m;++i) { mul=mul*a_m%p; if (hash[mul]) return i*m-(hash[mul]-1); } return -1; } int main() { scanf("%d%d",&T,&type); while (T--) { scanf("%lld%lld%lld",&y,&z,&p); switch(type) { case 1: { ans=fast_pow(y,z,p); printf("%lld\n",ans); break; } case 2: { ans=EXgcd(y,p,z); if (ans==-1) puts("Orz, I cannot find x!"); else printf("%lld\n",ans); break; } case 3: { ans=bsgs(y,z,p); if (ans==-1) puts("Orz, I cannot find x!"); else printf("%lld\n",ans); break; } } } }
相关文章推荐
- iOS 自定制搜索栏,保存历史搜索
- 9. UIActionSheet
- 基于uC/OSII多任务的STM32报警模块
- 修改div的透明度
- ubuntu14.04安装与配置cloudmonkey
- Linux基础命令(6)
- HBase超详细介绍
- input file 修改按钮名称
- 树状数组 + 位运算 LA 4013 A Sequence of Numbers
- 4281: [ONTAK2015]Związek Harcerstwa Bajtockiego 倍增LCA
- BZOJ 3910: 火车|LCA|并查集
- 关于php的语言结构和函数
- java.lang.IndexOutOfBoundsException: setSpan (26 ... 26) ends beyond length 10
- 单片机寄存器
- FM hal层的一些接口
- [XenServer] 修改默认安装XenServer系统盘(4G)大小
- Linux基础命令(5)
- CodeForces 614 A. Link/Cut Tree(水~)
- C语言学习笔记1-数据类型和标识符
- 对于ios7扫描二维码功能的实现