SDUTOJ Crack Mathmen(模拟,哈希表,快速幂)

题目连接:传送门

这一题是我们昨天省赛集训的题目,我可给坑惨了。不过所幸没有给白坑,学到了一些东西。最有感触的是这个

for(int i = 0 ; i < strlen(str); i++)   //危险,切勿模仿

如果数组大一些,这样写就直接超时。我之前找了好久都没发现,最后学长告诉我把他写成这样

int len = strlen(str);
for(int i = 0 ; i < len; i++)

为什么呢?原因是如果数组较大的话,那么就要计算 strlen(str)次的str的长度,这样会导致超时。但是如果将其保存在一个整型变量中,那么就只要计算一次str的长度就好了。这样就不会超时了。感觉自己瞬间就涨姿势了,之前可能是因为数组比较小,完全没有注意到这个,这一次数组大了一些,我可是吃尽了苦头。大家切记啊,不然准备好一晚上的时间来差错吧。

哈希表听起来是不是很高大上啊,用了这么久,现在才知道那玩意叫哈希表。不过哈希表的确是个好东西,他可以使你的查找时间是 O(1) ,为什么呢?因为他一次就可以找到了。我来说说哈希表吧,你一看,你就猛然一惊,怎么是这玩意。

哈希表(文字版):

在很多数据结构中(线性表,树等),记录在结构中的相对位置是随机的,和记录的关键字之间不存在确定关系,因此在结构中查找记录时,需要进行一系列和关键字的比较。这一类查找方法建立在比较的基础上,所以其查找的效率依赖于比较的次数。理想情况当然是不经任何比较,一次就得出结果。那就必须在记录的存储位置和他的关键字之间建立一个确定的对应关系 f ,使每一个关键字和结构中一个唯一的储存位置相对应。因此在查找时只要根据这个对应关系 f 就可以找到定值
K的像 f (K)。若结构中存在关键字与K相等的记录,则必定在 f(k)的储存位置上,所以我们一次就可以找到记录。我们称这个为 哈希函数。我们在使用中往往使用打表法与之结合,所以哈希表就诞生了。

哈希表(表达式版): f(key1) = key2 (这个表达式不是固定,我想说的是重点是建立一个映射关系,不管你的表达式是一次函数,还是二次,三次都行,这个根据需要来变化)

————————————————————分割线————————————————

瞎扯了很多,我们现在来看看题。题目想要你做的就是将一串密文还原。对于本题,因为还有一个 n 次方的问题 所以我们又要用到 快速幂 。不知道快速幂的请移步:这里

这一题我们可以这样处理,模拟他的加密方式将,他所用到的字符都进行加密,将其全部存起来,然后我们根据密文一个个的比较,比较时我们就可以使用哈希表,来提高效率。当然不使用这一题好像也能过,不过时间上那就......。所以我们还是用一下哈希表,这样快一些也方便。最后我们再将题目的细节处理一下这一题就完成了。对于 No Solution的情况,考虑一下,第一是将多解的删去,然后不再使用的字符 也删去。这一题就大圆满了。

代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MOD 997
#define MAXN 1000000 + 100
struct N{
    int x;
    char c;
}List_char[62]; //用结构体将字符,与其对应的加密后的文本存进结构体数组
char str[MAXN],Outstr[MAXN/3]; //str为输入文本,Outstr为输出文本
int ASC[MAXN/3],Hash[997],flog; //ASC存每个字母的加密文本,Hash为加密的密文与其数组下标的哈希表
int mod_pow(int x, int n){      //快速幂
    int res = 1;
    while( n > 0 ){
        if( n & 1 ) res = res * x % MOD;
        x = x * x % MOD;
        n >>= 1;
    }
    return res;
}

int cmp(const void* a, const void* b){
    struct N* A = (struct N*)a;
    struct N* B = (struct N*)b;
    if(A->x == B->x)
        flog = 1; //如果处在多解,这flog = 1
    return A->x - B->x;
}
int main(){
    int T, n, len;
    int i, j;
    //将字符保存进结构体中
    for(i = 0; i < 62; i++){
        if(i < 10)
            List_char[i].c = '0' + i;
        else if(i < 36)
            List_char[i].c = 'A' + i - 10;
        else
            List_char[i].c = 'a' + i - 36;
    }
    scanf("%d",&T);
    while(T--&&scanf("%d",&n)){
        flog = 0;   //初始化为0
        memset(Hash,0,sizeof(Hash));
        for(i = 0; i < 62; i++)
            List_char[i].x = mod_pow((int)List_char[i].c,n); //将字符转化为密文存入结构体中
        qsort(List_char,62,sizeof(List_char[0]),cmp);
        for(i = 0; !flog && i < 62; i++)   //如果不处在多解,这建立哈希表
            Hash[List_char[i].x] = i + 1;
        getchar();
        scanf("%s",str);
        len = strlen(str);
        for( i = 0, j = 0; j < len/3 && i + 2 < len; i+=3, j++ )
            ASC[j] = (str[i] - '0')*100 + (str[i+1] - '0')*10 + str[i+2] - '0';
        for( i = 0, j = 0; i < len/3; i++ ){
            if(Hash[ASC[i]])
                Outstr[j++] = List_char[Hash[ASC[i]] - 1].c;
            else
                flog = 1;   //密文有误
        }
        if(flog) printf("No Solution\n");
        else{
            for(i = 0; i < j; i++)
                printf("%c",Outstr[i]);
            printf("\n");
        }
    }
    return 0;
}

(如有错误,欢迎指正,转载请注明出处)



时间: 2024-10-07 08:59:29

SDUTOJ Crack Mathmen(模拟,哈希表,快速幂)的相关文章

UVA 11582 Colossal Fibonacci Numbers!(打表+快速幂)

Colossal Fibonacci Numbers! The i'th Fibonacci number f (i) is recursively defined in the following way: f (0) = 0 and f (1) = 1 f (i+2) = f (i+1) + f (i)  for every i ≥ 0 Your task is to compute some values of this sequence. Input begins with an int

UVA10006 - Carmichael Numbers(筛选构造素数表+快速幂)

UVA10006 - Carmichael Numbers(筛选构造素数表+快速幂) 题目链接 题目大意:如果有一个合数,然后它满足任意大于1小于n的整数a, 满足a^n%n = a;这样的合数叫做Carmichael Numbers.题目给你n,然你判断是不是Carmichael Numbers. 解题思路:首先用筛选法构造素数表,判断n是否是合数,然后在用快速幂求a^2-a^(n - 1)是否满足上述的式子.快速幂的时候最好用long long ,防止相乘溢出. 代码: #include <

POJ 3641 素数打表+快速幂 简单题

给出2个数,p和a,2<p<=1e9,1<a<p 若p满足下面2个条件,输出yes,否则输出no 1.p不是素数 2.有a^p=a(mod p) 先判断第一个条件: 本来想用一个数组is_prime[i]表示i是不是素数的,明显,这里p太大,数组开不下 若p不是素数的话, 则p必有p=b*c,其中b<=c, 则(sqrt(p))^2=b*c,则b<=sqrt(p)<=10^4.5<10^5 所以若在10^5内存在数b满足b<p&&p%b

840. 模拟哈希表(模板)

维护一个集合,支持如下几种操作: “I x”,插入一个数x: “Q x”,询问数x是否在集合中出现过: 现在要进行N次操作,对于每个询问操作输出对应的结果. 输入格式 第一行包含整数N,表示操作数量. 接下来N行,每行包含一个操作指令,操作指令为”I x”,”Q x”中的一种. 输出格式 对于每个询问指令“Q x”,输出一个询问结果,如果x在集合中出现过,则输出“Yes”,否则输出“No”. 每个结果占一行. 数据范围 1≤N≤1051≤N≤105−109≤x≤109−109≤x≤109 输入样

SDUT2165:Crack Mathmen(快速幂)

题目:http://acm.sdut.edu.cn/sdutoj/showproblem.php?pid=2165&cid=1431 快速幂. #include <iostream> #include <string.h> #include <stdlib.h> #include <stdio.h> #include <queue> #include <vector> #include <algorithm> #i

[Codevs 1230]元素查找(手写哈希表)

题目连接:http://codevs.cn/problem/1230/ 说白了就是要我们自己手写一个哈希表的数据结构来实现添加和查找功能,map也能直接过(我第一次写就是用map骗AC的) 提一下个人理解的哈希表的实现(下面说的是线性寻址法),如果有误还请各位大神不吝指教 用一个数组模拟哈希表,函数f(x)=数字x在哈希表中出现的下标的最小可能值,一般f(x)=x mod t,t就是哈希表的长度 下面就是一个哈希表的示例,如果遍历哈希表时指针走出了哈希表的终点,就进入起点重新遍历 对于每次向哈希

第二届山东省ACM省赛回顾 Crack Mathmen(打表)

Crack Mathmen 题目链接:http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2165 Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 Since mathmen take security very seriously, they communicate in encrypted messages. They cipher

noip模拟赛 好元素 哈希表的第一题

这是一道关于 题2好元素 2s [问题描述] 小A一直认为,如果在一个由N个整数组成的数列{An}中,存在以下情况: Am+An+Ap = Ai (1 <= m, n, p < i <= N , m,n,p可以相同),那么Ai就是一个好元素. 现在小A有一个数列,请你计算数列中好元素的数目 [输入格式] 第一行只有一个正整数N,意义如上. 第二行包含N个整数,表示数列{An}. [输出格式] 输出一个整数,表示这个数列中好元素的个数. [输入样例] Sample1 2 1 3 Sampl

HDU4887_Endless Punishment_BSGS+矩阵快速幂+哈希表

2014多校第一题,当时几百个人交没人过,我也暴力交了几发,果然不行. 比完了去学习了BSGS才懂! 题目:http://acm.hdu.edu.cn/showproblem.php?pid=4887 Endless Punishment Time Limit: 30000/15000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 52    Accepted Submissi