sdut2165——Crack Mathmen(快速幂+打表)

来源:互联网 发布:windows xp sp3 激活 编辑:程序博客网 时间:2024/06/05 06:13

Crack Mathmen

Time Limit: 1000MS Memory Limit: 65536KB
SubmitStatisticDiscuss

Problem Description

 Since mathmen take security very seriously, they communicate in encrypted messages. They cipher their texts in this way: for every characther c in the message, they replace c with f(c) = (the ASCII code of c)n mod 1997 if f(c) < 10, they put two preceding zeros in front of f(c) to make it a three digit number; if 10 <= f(c) < 100, they put one preceding zero in front of f(c) to make it a three digit number.

For example, if they choose n = 2 and the message is "World" (without quotation marks), they encode the message like this:

1. the first character is 'W', and it's ASCII code is 87. Then f(′W′) = 87^2 mod 997 = 590.

2. the second character is 'o', and it's ASCII code is 111. Then f(′o′) = 111^2 mod 997 = 357.

3. the third character is 'r', and it's ASCII code is 114. Then f(′r′) = 114^2 mod 997 = 35. Since 10 <= f(′r′) < 100, they add a 0 in front and make it 035.

4. the forth character is 'l', and it's ASCII code is 108. Then f(′l′) = 108^2 mod 997 = 697.

5. the fifth character is 'd', and it's ASCII code is 100. Then f(′d′) = 100^2 mod 997 = 30. Since 10 <= f(′d′) < 100, they add a 0 in front and make it 030.

6. Hence, the encrypted message is "590357035697030".

One day, an encrypted message a mathman sent was intercepted by the human being. As the cleverest one, could you find out what the plain text (i.e., the message before encryption) was?

Input

 The input contains multiple test cases. The first line of the input contains a integer, indicating the number of test cases in the input. The first line of each test case contains a non-negative integer n (n <= 10^9). The second line of each test case contains a string of digits. The length of the string is at most 10^6.

Output

 For each test case, output a line containing the plain text. If their are no or more than one possible plain text that can be encrypted as the input, then output "No Solution" (without quotation marks). Since mathmen use only alphebetical letters and digits, you can assume that no characters other than alphebetical letters and digits may occur in the plain text. Print a line between two test cases.

Example Input

3259035703569703000010010010010011000000000001001001001001

Example Output

WorldNo SolutionNo Solution

分析:题意是,对字母和数字进行编码,每个字母或数字的编码都是三位,编码规则为该字符的ASCII值的n次方mod 997。并保证对每个字符(只包括字母和数字)的编码存在且唯一,若译码结果不是字符或数字则输出No Solution

用快速幂求出相应的编码,再用编码做为数字下表存字符,例如ch[ 590 ]='W';

#include <iostream>#include <cstdio>#include <cstring>#include <queue>#include <cmath>#include <algorithm>#include <vector>#include <map>#include <string>#include <stack>using namespace std;typedef long long ll;#define PI 3.1415926535897932#define E 2.718281828459045#define INF 0xffffffff//0x3f3f3f3f#define mod 997const int M=1005;int n,m;int cnt;int sx,sy,sz;int mp[1000][1000];int pa[M*10],rankk[M];int head[M*6],vis[M*100];int dis[M*100];ll prime[M*1000];bool isprime[M*1000];int lowcost[M],closet[M];char st1[5050],st2[5050];int len[M*6];typedef pair<int ,int> ac;//vector<int> g[M*10];ll dp[1000][2000];int has[10500];int month[13]= {0,31,59,90,120,151,181,212,243,273,304,334,0};int dir[8][2]= {{0,1},{0,-1},{-1,0},{1,0},{1,1},{1,-1},{-1,1},{-1,-1}};void getpri(){    ll i;    int j;    cnt=0;    memset(isprime,false,sizeof(isprime));    for(i=2; i<1000000LL; i++)    {        if(!isprime[i])prime[cnt++]=i;        for(j=0; j<cnt&&prime[j]*i<1000000LL; j++)        {            isprime[i*prime[j]]=1;            if(i%prime[j]==0)break;        }    }}struct node{    int v,w;    node(int vv,int ww)    {        v=vv;        w=ww;    }};vector<int> g[M*100];char str[10000005];int bit[50];char str01[1000005],strr[1000005];int qmod(int x,int b){    int ans=1;    while(b)    {        if(b&1)            ans=(ans*x)%mod;        x=(x*x)%mod;        b>>=1;    }    return ans%mod;}bool init(){ //打表    int p;    memset(str01,'\0',sizeof(str01));    for(int i=32;i<=126;i++){//键盘上存在字符的asc码表          p=qmod(i,n);        if(str01[p]=='\0')//判断 原码 ->加密码 转换过程中是否重复,重复则直接返回false            str01[p]=char(i);//  加密码 作数组下标,匹配时直接寻找,无需查找        else return false;//保证对每个字符(只包括字母和数字)的编码存在且唯一    }    return true;}ll sum[5000],a[5000];int main(){    int i,j,k,t;    bool flag;    scanf("%d",&t);    while(t--)    {       flag=true;       memset(strr,0,sizeof(strr));       j=0;       scanf("%d",&n);       //if(n==0)       scanf("%s",str);       if(n==0){printf("No Solution\n");continue;}       int len=strlen(str);       if(init()){          for(i=0;i<len;i+=3){//每三个确定一个字符             int tmp=(str[i]-'0')*100+(str[i+1]-'0')*10+(str[i+2]-'0');             if(str01[tmp]=='\0'){//不存在字符源码                flag=false;                break;             }             strr[j++]=str01[tmp];//把翻译过来的存一下 好输出          }       }       else flag=false;       if(flag)printf("%s\n",strr);//要么就for循环输出,上边就不用memset了,否则WA出血。。。       else printf("No Solution\n");    }    return 0;}
0 0
原创粉丝点击