Hdu3223 Decrypt Messages

Decrypt Messages

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 657    Accepted Submission(s): 158

Problem Description
In the game BioHazard 4, the president's daughter has been abducted by some crazy villagers. Leon S. Kennedy, the secret agent of White House, goes to rescue her. He keeps in contact with Hunnigan, the president's secretary.

But the time in their contact log has been encrypted, using the following method:

Count the number of seconds from 2000.01.01 00:00:00 to that time, assume this number is x. Then calculate xq, modulo it by a prime number p. The remainder a is the encrypted number.

Your task is to help Leon write a program to decrypt the contact log, and tell him all the possible original time.

1. Remember that if the year can be divided evenly by 4 but can't be divided evenly by 100, or it can be divided evenly by 400, this year is a leap year. The February of a leap year has 29 days, while the February of other years has 28 days.

2. In this problem, if the year modulo 10 is 5 or 8, at the end of this year, there is one “leap second”, i.e., the second after 2005.12.31 23:59:59 is 2005.12.31 23:59:60, and after that second, it's 2006.01.01 00:00:00.
You may assume that from 2000.01.01 00:00:00 till that time, less than p seconds have passed.
 
Input
There are multiple test cases.
The first line of the input contains an integer T, meaning the number of the test cases.

For each test case, a single line of three integers: p, q, and a. (2<p≤1000000007, 1<q≤10, 0≤a<p, p is always a prime.)
 
Output
The time. If there are multiple solutions, you must output all possible solutions in chronological order.

If the solution doesn't exist, output Transmission error instead.
See the sample output for further details.
 
Sample Input
2 3 2 1 3 2 2
 
Sample Output
Case #1: 2000.01.01 00:00:01 2000.01.01 00:00:02 Case #2: Transmission error
 
Source
 
Recommend
zhuweicong
题目大意:解方程:x^q = a (mop p),求从2000.01.01 00:00:00过x秒后的时间.
分析:综合性非常强的一道题,解这种n次剩余方程有固定的解法.
          先求出p的原根g,方法就是枚举g,然后检验它是不是原根,检验方法是枚举p-1的质因子a,如果g^((p-1)/a) = 1 (mod p),那么g就不是原根.然后令g^y = x,g^t = a,原方程就转化为yq = a (mod (p-1)).a是给定的,t可以用bsgs算出来.y就可以通过扩展欧几里得算法求出来了.因为题目要求所有解,所以最后要从最小正整数解通过枚举倍数来生成其他的解.
          在求解的时候需要及时地判断是否有解,最主要的判断是有没有原根,bsgs能不能求出解,扩欧能不能求出来.
#include <cstdio>
#include <cmath>
#include <vector>
#include <map>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;
typedef long long ll;
ll p,q,a,g,t;
int T,cas;
vector <ll> yinzi,endd;
map <ll,ll> bsg;

ll qpow(ll a,ll b,ll mod)
{
    ll res = 1;
    while(b)
    {
        if (b & 1)
            res = (res * a) % mod;
        a = (a * a) % mod;
        b >>= 1;
    }
    return res;
}

ll exgcd(ll a,ll b,ll &x,ll &y)
{
    if (!b)
    {
        x = 1;
        y = 0;
        return a;
    }
    ll temp = exgcd(b,a % b,x,y),t = x;
    x = y;
    y = t - (a / b) * y;
    return temp;
}

bool check(ll x)
{
    ll t = p - 1;
    for (int i = 0; i < yinzi.size(); i++)
        if (qpow(x,t / yinzi[i],p) == 1)
        return false;
    return true;
}

ll getyuangen()
{
    ll x = p - 1;
    yinzi.clear();
    for (ll i = 2; i <= sqrt(x); i++)
        if(x % i == 0)
        {
            yinzi.push_back(i);
            while(x % i == 0)
                x /= i;
        }
        if (x != 1)
            yinzi.push_back(x);
    ll temp = 0;
    while(++temp)
        if (check(temp))
        return temp;
}

ll bsgs()
{
    bsg.clear();
    if (g % p == 0)
        return -1;
    ll block = ceil(sqrt(p));
    ll ans;
    for (ll i = 0; i <= block; i++)
    {
        if (i == 0)
        {
            ans = a % p;
            bsg[ans] = i;
            continue;
        }
        ans = (ans * g) % p;
        bsg[ans] = i;
    }
    ll temp = qpow(g,block,p);
    ans = 1;
    for (ll i = 1; i <= block; i++)
    {
        ans = (ans * temp) % p;
        if (bsg[ans])
        {
            ll anss = i * block - bsg[ans];
            return (anss % p + p) % p;
        }
    }
    return -1;
}

void solve()
{
    endd.clear();
    ll A = q,B = p - 1,C = t,x,y;
    ll d = exgcd(A,B,x,y);
    if (C % d == 0)
    {
        x = (x % B + B) % B;
        endd.push_back(x * (C / d) % B);
        for (ll i = 1; i < d; i++)
            endd.push_back((endd[0] + i * B / d) % B);
    }
}

int dd[33],hh[30],mi[80];
int mm[20]={0,31,28,31,30,31,30,31,31,30,31,30,31};
void print(ll x){
    int y,mo,d,h,min,s,i;
    for(y=2000;1;y++){
        s=365*24*60*60;
        if(y%4==0&&y%100||y%400==0)
            s+=24*60*60;
        if(y%10==5||y%10==8)
        s++;
        if(x-s<0)
        break;
        x-=s;
    }
    if(y%4==0&&y%100||y%400==0)
        for(i=2;i<13;i++)
            mm[i]+=24*60*60;
    if(y%10==5||y%10==8){
        mm[12]++;
        dd[31]++;
        hh[24]++;
        mi[60]++;
    }
    for(i=1;i<13;i++)
        if(x-mm[i]<0)
        break;
    x-=mm[i-1];
    mo=i;
    for(i=1;i<33;i++)
        if(x-dd[i]<0)
        break;
    x-=dd[i-1];
    d=i;
    for(i=1;i<25;i++)
        if(x-hh[i]<0)
        break;
    x-=hh[i-1];
    h=i-1;
    for(i=1;i<61;i++)
        if(x-mi[i]<0)
        break;
    x-=mi[i-1];
    min=i-1;
    if(y%4==0&&y%100||y%400==0)
        for(i=2;i<13;i++)
            mm[i]-=24*60*60;
    if(y%10==5||y%10==8){
        mm[12]--;
        dd[31]--;
        hh[24]--;
        mi[60]--;
    }
    printf("%d.%02d.%02d %02d:%02d:%02lld\n",y,mo,d,h,min,x);
}

void init()
{
    bsg.clear();
    yinzi.clear();
    endd.clear();
    p = q = a = g = t = 0;
}

int main()
{
    for(int i=1;i<15;i++)mm[i]=mm[i]*24*60*60+mm[i-1];
    for(int i=1;i<33;i++)dd[i]=i*24*60*60;
    for(int i=1;i<30;i++)hh[i]=i*60*60;
    for(int i=1;i<80;i++)mi[i]=i*60;
    scanf("%d",&T);
    while(T--)
    {
        ++cas;
        init();
        scanf("%lld%lld%lld",&p,&q,&a);
        printf("Case #%d:\n",cas);
        if (a == 0)
        {
            printf("2000.01.01 00:00:00\n");
            continue;
        }
        g = getyuangen();
        t = bsgs();
        if (t == -1)
        {
            printf("Transmission error\n");
            continue;
        }
        solve();
        if(endd.size() == 0)
        {
            printf("Transmission error\n");
            continue;
        }
        for (int i = 0; i < endd.size(); i++)
            endd[i] = qpow(g,endd[i],p);
        sort(endd.begin(),endd.end());
        for (int i = 0; i < endd.size(); i++)
            print(endd[i]);
    }

    return 0;
}

 

posted @ 2017-12-22 23:56  zbtrs  阅读(271)  评论(0编辑  收藏  举报