codevs1928 加密算法 数论[四星]
来源:互联网 发布:十二宫杀手解析知乎 编辑:程序博客网 时间:2024/05/22 01:51
题目链接:CodeVs
妈呀长知识了……
题目描述 Description
Rivest是密码学专家。近日他正在研究一种数列E={E[1],E[2],……,E[n]},且E[1]=E[2]=p(p为一个质数),E[i]=E[i-2]*E[i-1] (若2 < i<=n)。例如{2,2,4,8,32,256,8192,……}就是p=2的数列。在此基础上他又设计了一种加密算法,该算法可以通过一个密钥q ( q < p )将一个正整数n加密成另外一个正整数d,计算公式为:d=E[n] mod q。现在Rivest想对一组数据进行加密,但他对程序设计不太感兴趣,请你帮助他设计一个数据加密程序。
输入描述 Input Description
读入m,p。其中m表示数据个数,p用来生成数列E。以下有m行,每行有2个整数n,q。n为待加密数据,q为密钥。
规模:0
输出描述 Output Description
将加密后的数据按顺序输出到文件a.out。
第i行输出第i个加密后的数据。
样例输入 Sample Input
2 7
4 5
4 6
样例输出 Sample Output
3
1
数据范围及提示 Data Size & Hint
无
题解:
首先看题目,暴力枚举模拟基本没分……20个点说不定也可以水一点分,所以我们不考虑暴力。
对于题目中隐含的公式:E[i] = E[i-1]*E[i-2];
虽然看起来和fib没有什么关系,也不能直接推矩阵公式,但是我们拆开后发现每一项都是题目给出p的fib级。
这么说难以理解,直接模拟一下:
E[1] = p;
E[2] = p;
E[3] = E[2] * E[1] = p ^ 2 = p ^ (fib(3));
E[4] = E[3] * E[2] = p ^ 3 = p ^ (fib(4));
E[5] = E[4] * E[3] = p ^ 5 = p ^ (fib(5));
……
……
……
那么题目给定的原公式就可以化简一下:
d=E[n] mod q ——–> d = p^fib(n) % q;
经过fib转化后就可以用钜乘了,但是还有一个问题,这里乱取膜真的没问题吗?
我的第一代想法就是 p ^ fib(n) % q == (p%q) ^ (fib(n) % q) % q,但是被神犇Archon告知这样是完全错误的……
于是她安利了我一个公式 :
这是正确姿势,于是我就比这个打,然后以前只会筛,现在也学会了根号n求欧拉函数,感觉收获挺大的~
钜乘什么的以前写过多次了,这里就是要注意多组数据每次都清掉以前的结果就行了~
下面写一下如何根号n求phi(n);
定理:1、若 p 是质数,φ(p)= p-1.
2、若 n 是质数 p 的 k 次幂,φ(n)= (p-1)p^(k-1)
因为除了 p 的倍数都与 n 互质
因为n % p == 0只可能存在于[1,sqrt(n)];所以算法复杂度是sqrt(n)~
下面写一下:
int get(int n){ int ret = 1; for(int i = 2;i*i <= n;i ++) { if(n % i == 0) { n /= i,ret *= (i-1);//定理2 while(n % i == 0) n /= i,ret *= i;//定理2 } } if(n > 1) ret *= (n-1); return ret;}
下面附上完整代码:
#include<iostream>#include<cstdio>#include<cstring>#include<queue>#include<stack>#include<algorithm>using namespace std;typedef unsigned long long LL;LL mod,phimod;struct juzhen{ LL num[3][3]; LL n,m; juzhen(){memset(num,0,sizeof(num)); n= 0,m = 0;};};juzhen operator * (juzhen a,juzhen b){ juzhen ans; ans.n = a.n,ans.m = b.m; for(int i = 1;i <= a.n;i ++) { for(int j = 1;j <= b.m;j ++) { ans.num[i][j] = 0; for(int k = 1;k <= a.m;k ++) { ans.num[i][j] = (ans.num[i][j]%phimod + ((a.num[i][k]%phimod)*(b.num[k][j]%phimod))%phimod)%phimod; }// cout<<ans.num[i][j]<<"QAQ"<<endl; } } return ans;}juzhen fib,tmp;int get(int n){ int ret = 1; for(int i = 2;i*i <= n;i ++) { if(n % i == 0) { n /= i,ret *= (i-1); while(n % i == 0) n /= i,ret *= i; } } if(n > 1) ret *= (n-1); return ret;}void ksm(LL k){ while(k) { if(k & 1) fib = fib * tmp; tmp = tmp * tmp; k >>= 1; }}LL kusm(LL a,LL b){ LL ans = 1; while(b) { if(b & 1) ans = ((ans%mod)*(a%mod))%mod; a = ((a%mod)*(a%mod))%mod; b >>= 1; } return ans;}LL m,p,n;int main(){ ios::sync_with_stdio(0); cin>>m>>p; while(m--) { fib.n = 1,fib.m = 2; fib.num[1][1] = fib.num[1][2] = 1; tmp.n = tmp.m = 2; tmp.num[1][1] = tmp.num[1][2] = tmp.num[2][1] = 1; tmp.num[2][2] = 0; cin>>n>>mod; phimod = get(mod);// cout<<mod<<"QAQ"<<endl; if(n >= 3LL) ksm(n-2); LL cifang = fib.num[1][1] + phimod; LL ans = kusm(p,cifang); cout<<ans<<endl; } return 0;}
NOIP ;Bless All ;RP++;
- codevs1928 加密算法 数论[四星]
- 加密算法6《四》
- 对称加密算法的四种应用模式
- 四种加密算法之SHA1源代码-C++
- 四种加密算法之DES源代码-C++
- 四种加密算法之RSA源代码-C++
- 四种加密算法之SHA1源代码-C++
- 四种加密算法之RSA源代码-C++
- 四种加密算法之SHA1源代码-C++
- 四种加密算法之DES源代码-C++
- 四种加密算法之RSA源代码-C++
- 四种加密算法之SHA1源代码-C++
- 四种加密算法之DES源代码-C++
- 数论之欧几里德算法(四)
- hihocoder 数论四·扩展欧几里德
- 数论基本定理及应用(四)
- hiho 1297 数论四·扩展欧几里得
- HIHO #1297 : 数论四·扩展欧几里德
- centos pil
- 高效开发Android App的10个建议
- spring 自定义bean初始化及析构方法
- 技术人员硬实力和软实力
- Objective-C中的Protocol
- codevs1928 加密算法 数论[四星]
- 【HNOI2012】【BZOJ2732】射箭
- 解决android中软件盘弹出导致的控件位置问题
- C++学习——copy构造函数及浅拷贝和深拷贝
- qt creator 在linux系统加载动态连接库
- 解压
- 编码问题:unicode与utf-8,wchar_t与char
- Android 动画实践
- 进击的KFC:OC(六)Block