例题6.20 信息解密 UVa1457
来源:互联网 发布:海南知和行书局 编辑:程序博客网 时间:2024/06/16 19:32
1.题目描述:点击打开链接
2.解题思路:本题是一道模拟+数论的综合题。因此可以数论部分和模拟部分分开进行。首先,除去日历,其实本题就是要求解x^q≡a (mod p)。这需要用到数论中原根的知识,读者可以网上或者初等数论书中找到相应的内容。假设我们现在已经有了p的原根m,那么该如何求解呢?可以用离散对数的方法来做,方程两边同时取m的离散对数,得q*x'≡a'(mod p-1)。这里的x'就是x以m为底模p的离散对数,a'同理。这样问题就转化为求解线性同余方程了。不难得到该方程的所有解系,一共有gcd(q,p-1)个解。有了这些解,就可以开始模拟时间了。
本题对时间的模拟细节比较多,首先需要处理年份是否为闰年,还要考虑一年中是否存在闰秒。为了便于处理,我们可以事先对每个月的天数打表,并把1天的秒数设为一个常量。这样,第一步先从解中不断地减去一年的秒数来获得是第几年,用同样的方法获得第几个月,如果发现恰好是闰秒,就单独输出,否则继续按照上述方法得到时分秒。最后输出即可。详细细节见代码。
本题求原根利用rand()函数生成测试来求解,因为原根在2~MOD-1之间,因此这种方法的效率还是比较高的。
3.代码:
#include<iostream>#include<algorithm>#include<cassert>#include<string>#include<sstream>#include<set>#include<bitset>#include<vector>#include<stack>#include<map>#include<queue>#include<deque>#include<cstdlib>#include<cstdio>#include<cstring>#include<cmath>#include<ctime>#include<cctype>#include<functional>#pragma comment(linker, "/STACK:1024000000,1024000000")using namespace std;#define me(s) memset(s,0,sizeof(s))#define rep(i,n) for(int i=0;i<(n);i++)typedef long long ll;typedef unsigned int uint;typedef unsigned long long ull;typedef pair <int, int> P;const int SECONDS_PER_DAY=24*60*60;const int num_days[]={31,28,31,30,31,30,31,31,30,31,30,31};bool is_leap(int year){ if(year%400==0)return true; if(year%4==0)return year%100!=0; return false;}int leap_second(int year,int month){ return ((year%10==5||year%10==8)&&month==12)?1:0;}void print(int year,int month,int day,int hh,int mm,int ss){ printf("%d.%02d.%02d %02d:%02d:%02d\n",year,month,day,hh,mm,ss);}void print_time(ll t)//从t中解析年,月,日,时,分,秒{ int year=2000; while(1) { int days=is_leap(year)?366:365; ll sec=(ll)days*SECONDS_PER_DAY+leap_second(year,12); if(t<sec)break; t-=sec; year++; } int month=1; while(1) { int days=num_days[month-1]; if(is_leap(year)&&month==2)days++; ll sec=(ll)days*SECONDS_PER_DAY+leap_second(year,month); if(t<sec)break; t-=sec; month++; } if(leap_second(year,month)&&t==31*SECONDS_PER_DAY) print(year,12,31,23,59,60); else { int day=t/SECONDS_PER_DAY+1; t%=SECONDS_PER_DAY; int hh=t/(60*60); t%=60*60; int mm=t/60; t%=60; int ss=t; print(year,month,day,hh,mm,ss); }}ll gcd(ll a,ll b){ return !b?a:gcd(b,a%b);}void gcd(ll a,ll b,ll&d,ll&x,ll&y){ if(!b){d=a;x=1;y=0;} else {gcd(b,a%b,d,y,x);y-=x*(a/b);}}int pow_mod(ll a,ll p,int MOD){ ll ans=1; while(p>0) { if(p&1)ans=ans*a%MOD; a=a*a%MOD; p>>=1; } return ans;}int mul_mod(ll a,ll b,int MOD){ return a*b%MOD;}int inv(ll a,int MOD){ ll d,x,y; gcd(a,MOD,d,x,y); return (x+MOD)%MOD;}int log_mod(int a,int b,int MOD)//求离散对数{ int m,v,e=1,i; m=(int)sqrt(MOD); v=inv(pow_mod(a,m,MOD),MOD); map<int,int>x; x[1]=0; for(int i=1;i<m;i++) { e=mul_mod(e,a,MOD); if(!x.count(e))x[e]=i; } for(int i=0;i<m;i++) { if(x.count(b))return i*m+x[b]; b=mul_mod(b,v,MOD); } return -1;}int get_primitive_root(int MOD,int phi)//求原根{ vector<int>factors; int n=phi; for(int i=2;i*i<=n;i++) { if(n%i)continue; factors.push_back(i); while(n%i==0)n/=i; } if(n>1)factors.push_back(n); while(1) { int m=rand()%(MOD-2)+2; bool ok=true; for(int i=0;i<factors.size();i++) if(pow_mod(m,phi/factors[i],MOD)==1){ok=false;break;} if(ok)return m; }}vector<ll> solve_linear_modular_equation(int a,int b,int n)//解线性同余方程{ vector<ll>ans; int d=gcd(a,n); if(b%d)return ans; a/=d,b/=d; int n2=n/d; int p=mul_mod(inv(a,n2),b,n2); for(int i=0;i<d;i++) ans.push_back(((ll)i*n2+p)%n); return ans;}vector<ll> mod_root(int a,int q,int p)//求底数{ vector<ll>ans; if(!a) { ans.push_back(0); return ans; } int m=get_primitive_root(p,p-1); int z=log_mod(m,a,p); ans=solve_linear_modular_equation(q,z,p-1); for(int i=0;i<ans.size();i++) ans[i]=pow_mod(m,ans[i],p); sort(ans.begin(),ans.end()); return ans;}int main(){ int T,P,Q,A; cin>>T; for(int kase=1;kase<=T;kase++) { cin>>P>>Q>>A; vector<ll>ans=mod_root(A,Q,P); printf("Case #%d:\n",kase); if(ans.empty()) puts("Transmission error"); else for(int i=0;i<ans.size();i++) print_time(ans[i]); }}
0 0
- 例题6.20 信息解密 UVa1457
- 加密解密、信息摘要
- DES信息加密解密
- 例题4-4 信息解码 UVa213
- 简单的信息加密解密
- 例题
- 例题
- 例题
- 例题
- 例题 4-4 信息解码 (Message Decoding) UVa 213
- 例题 4-4 信息解码 (Uva 213)
- 加密解密、信息摘要算法收集
- 加密解密、信息摘要算法收集
- 加密解密信息摘要算法搜集
- 加密解密、信息摘要常用算法收集~~
- PHP对信息加解密函数
- 加解密web.config文件重要信息
- 加密解密、信息摘要常用算法收集~~
- 面试题26:复杂链表复制
- OSSchedLock()函数透析 转自:跳跳盆盆——博客园http://www.cnblogs.com/pengwangguoyh/p/4446024.html
- 解决VS2010链接错误:LINK : fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏
- C#中的线程(二) 线程同步基础
- 采样示波器和实时示波器的原理与各自优势
- 例题6.20 信息解密 UVa1457
- createrepo and smart channel
- NOIP2012国王游戏
- 轻松python之文件专题-搜索文本并写入文件专题
- 数据结构基础 之 双链表
- Collection之List Vector ArrayList and linkedList
- 【后缀数组】 POJ 3882 Stammering Aliens 可重叠出现k次字符串
- maven仓库查询地址
- Android项目开发实战:倒计时