例题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
原创粉丝点击