😐🙂😄🤗:快乐程度依次增加。
——以下题目均来自于PAT甲级题库。
🙂1014.Waiting in Line (30分)(队列)
可以发现这一题中,有一个排队的模型,这可以提示我们使用队列这个数据结构,我们用队列维护黄线内每个窗口的排队情况。注意这题在8点的时候这一天所有的人都已经排着队了,这些人中的前n*m个会排到黄线的前面,后面的在黄线后面,显然对这两波人的操作是不同的。对于前n*m个人,我们直接找到黄线前排队人数最少的窗口即可(如果该窗口不止一个就找id最小的)。而对于后面的人来说,由于此时黄线内已经排满了人,因此就得看哪个窗口最先服务完就排到哪里去,因此这里就需要比较每个队列队头元素的大小找出队头最先服务完的队列,然后排过去即可。
代码
Waiting in Line 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 #include <iostream> #include <queue> #include <algorithm> #include <map> using namespace std ;const int N = 30 ;int n,m,k,Q;int fin[N];map <int ,int > res;queue <int > q[N];int main () { cin >>n>>m>>k>>Q; for (int i=1 ;i<=k;i++){ int c; cin >>c; int t=0 ; for (int j=0 ;j<n;j++){ if (i<=n*m){ if (q[t].size ()>q[j].size ()) t=j; }else { if (q[t].front()>q[j].front()) t=j; } } fin[t]+=c; if (i>n*m) q[t].pop(); q[t].push(fin[t]); if (fin[t]-c<540 ) res[i]=fin[t]; } for (int i=0 ;i<Q;i++){ int c; cin >>c; if (res.count(c)) printf ("%02d:%02d\n" ,res[c]/60 +8 ,res[c]%60 ); else puts ("Sorry" ); } return 0 ; }
🙂1060 Are They Equal (25分)(字符串处理)
对于这道题需要注意的是保留有效数字并不需要像数学上那样还做什么四舍五入,只是单纯的截断而已。也就是说这题核心就是要把给定的数字转换成题目中给出的表示形式。转换的步骤大致如下:
找到小数点的位置k,然后去掉小数点。 (如果该数是整数没有小数点那么在最末尾加上一个小数点)
由于可能存在前导0,那么每次去掉一个前导0然后k就-1。(前导0本身的存在不影响数字的大小,k是直接拿到的小数点在数字中的位置,因此这部分位置是包含了前导0的位置的,因此只有把前导0的位置去掉此时才是正确的大小)。到这一步实际上可以理解为就是把数字先转化成了"科学计数法"的形式,得到了小数部分和幂指部分。
由于要求保留n位有效数字,所以我们把数字截取n位,如果数字剩下部分不足n位则要在其后补0凑足n位。这一步是在对上面的数字做截取。
把答案拼凑起来。
值得注意一下,上面步骤的前两步就是把一个数(整数或者小数)化成0.abc * 10 ^ k (a不等于0)形式的一个比较好的做法。
代码
Are They Equal 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #include <iostream> #include <algorithm> #include <cstring> using namespace std ;string toans (string s,int n) { int k=s.find ('.' ); if (k==-1 ) s+='.' ,k=s.find ('.' ); s=s.substr(0 ,k)+s.substr(k+1 ); while (s.size ()&&s[0 ]=='0' ) s.erase(0 ,1 ),k--; if (!s.size ()) k=0 ; s=s.substr(0 ,n); s+=string (n-s.size (),'0' ); s="0." +s+"*10^" +to_string(k); return s; } int main () { int n; string a,b; cin >>n>>a>>b; a=toans(a,n); b=toans(b,n); if (a==b) cout <<"YES " <<a; else cout <<"NO " <<a<<" " <<b; return 0 ; }
😐1077 Kuchiguse (20分)(字符串处理)
这一题的思路,即首先遍历后缀的长度,然后依次取所有串该长度的后缀,看看是否都相等,并找出最长的后缀。
Kuchiguse 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 #include <iostream> #include <vector> #include <string> #include <algorithm> using namespace std ;int main () { int n; vector <string > v; cin >>n; string line ; getline(cin ,line ); while (n--){ getline(cin ,line ); v.push_back(line ); } for (int k=v[0 ].size ();k;k--){ string t=v[0 ].substr(v[0 ].size ()-k); bool succ=true ; for (int i=1 ;i<v.size ();i++){ if (v[i].size ()<k||v[i].substr(v[i].size ()-k)!=t){ succ=false ; break ; } } if (succ){ puts (t.c_str()); return 0 ; } } puts ("nai" ); return 0 ; }
🙂1082.Read Number in Chinese (25分)(字符串处理)
我们可以发现每四位的读法其实是一样的,因此我们可以把数字分成3份(每四个数字为一份),然后先正常读每一份,然后在每一份的结尾判断是否加上相应的单位("亿","万","")。
注意读的时候对"读0"有这样的规则需要准守:
碰到连续的0时只读一个0。
末尾不能有0出现。
代码
Read Number in Chinese 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 #include <iostream> #include <string> #include <vector> #include <algorithm> using namespace std ;string maps[]={"ling" ,"yi" ,"er" ,"san" ,"si" ,"wu" ,"liu" ,"qi" ,"ba" ,"jiu" };bool check (string s) { return s.size ()>=5 &&s.substr(s.size ()-5 )=="ling " ; } string get (int n) { vector <int > num; string unit[]={"" ,"Shi " ,"Bai " ,"Qian " }; while (n) num.push_back(n%10 ),n/=10 ; string res="" ; for (int i=num.size ()-1 ;i>=0 ;i--){ if (num[i]) res+=maps[num[i]]+" " ; else if (num[i]==0 &&!check(res)) res+="ling " ; if (num[i]) res+=unit[i]; } if (check(res)) res.erase(res.size ()-5 ); return res; } int main () { int n; cin >>n; string res="" ; if (n<0 ) res+="Fu " ; else if (n==0 ) res="ling " ; n=abs (n); string unit[]={"" ,"Wan" ,"Yi" }; vector <int > num; while (n) num.push_back(n%10000 ),n/=10000 ; for (int i=num.size ()-1 ;i>=0 ;i--){ if (num[i]){ string s=get (num[i]); if (num[i]<1000 &&res!="" &&res!="Fu " &&!check(res)) res+="ling " ; res+=s; } else if (num[i]==0 &&!check(res)) res+="ling " ; if (num[i]) res+=unit[i]+" " ; } if (res!="ling " &&check(res)) res.erase(res.size ()-5 ); while (res[res.size ()-1 ]==' ' ) res.pop_back(); cout <<res; return 0 ; }
😐1108.Finding Average (20分)(字符串处理)
这一题其实不怎么快乐,主要是想尝试下try-catch语法。思路大致就是把不合法的直接输出,把合法的加起来求平均值(好吧,这就是题面的意思)。
代码
Finding Average 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #include <iostream> using namespace std ;int main () { int n; cin >>n; double sum=0 ; int m=0 ; while (n--){ string s; cin >>s; bool succ=true ; float x; try { size_t cnt; x=stof(s,&cnt); if (cnt<s.size ()) succ=false ; }catch (...){ succ=false ; } int k=s.find ('.' ); if (k!=-1 &&s.size ()-k>3 ) succ=false ; if (x<-1000 ||x>1000 ) succ=false ; if (succ){ m++; sum+=x; } else printf ("ERROR: %s is not a legal number\n" ,s.c_str()); } if (m==1 ) printf ("The average of 1 number is %.2lf" ,sum/m); else if (m>1 ) printf ("The average of %d numbers is %.2lf" ,m,sum/m); else if (m==0 ) printf ("The average of 0 numbers is Undefined" ); return 0 ; }
😄1065 A+B and C (64bit) (20分)(long long的溢出)🌌
这里的两数相加会有两种溢出情况:
如果两个负数相加得到的结果是非负数,则溢出。
如果两个正数相加得到的结果是负数,则溢出。
因此在判断a+b>c的时候要注意考虑如上的两种情况,第一种是"无穷小"的情况,第二种是"无穷大"的情况,剩下的就是可以正常判断的情况。
当然这题并不是到这里就完了的,因为还有着几处奇奇怪怪的坑等着去踩💢💢💢❌❌❌具体见下面代码。
代码
A+B and C (64bit) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include <iostream> using namespace std ;typedef long long LL;bool check (LL a,LL b,LL c) { LL d = a+b; if (a>0 &&b>0 &&d<0 ) return true ; if (a<0 &&b<0 &&d>=0 ) return false ; return a+b>c; } int main () { int T; cin >>T; for (int i=1 ;i<=T;i++){ LL a,b,c; scanf ("%lld%lld%lld" ,&a,&b,&c); if (check(a,b,c)) printf ("Case #%d: true\n" ,i); else printf ("Case #%d: false\n" ,i); } return 0 ; }
😄1095.Cars on Campus (30分)(排序+hash)🌌
对于这道题大致的模拟过程是这样的:
首先过滤掉不合法的数据;
接着由于把时间转换成秒之后数据范围并不大,因此可以用hash来处理每个时刻停了多少辆车这个问题,我们只用先根据题意,每个时刻如果有车进那么该时刻的车辆数+1,如果车出则-1,然后再对整个时刻的数组做个前缀和,就可以得到每个时刻有多少量车了; 接着再遍历两遍数组,求出最大停车时长(注意可能多次停车,反正只要是合法的一对记录都要算上 )并且求出最大停车时长的车辆。
像这样需要求取合法的相邻时间对的题目已经碰到过几次了,在此总结一下如何优雅的求取合法的相邻时间对。
把A(如该题的A就是某个车牌号)相关的所有时间都存到一个数组中,然后将该数组从小到大排序,然后依次遍历数组找出那些连续的in,out对。(是否需要删除那些不合法的数据要看情况,有时可能没必要,当然这更取决于自己的实现方式了。)
代码
Cars on Campus 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 #include <iostream> #include <algorithm> #include <queue> #include <map> #include <string> using namespace std ;#define fi first #define se second struct Park { int t; bool st; bool operator < (const Park &p1) const { return t<p1.t; } }; map <string ,vector <Park>>maps;int get (vector <Park> &v) { int res=0 ; for (int i=0 ;i<v.size ();i+=2 ) res+=v[i+1 ].t-v[i].t; return res; } const int N=1e5 +10 ;int num[N];int main () { int n,k; cin >>n>>k; while (n--){ string id,t,st; cin >>id; int hh,mm,ss; scanf ("%d:%d:%d" ,&hh,&mm,&ss); cin >>st; maps[id].push_back({hh*3600 +mm*60 +ss,st[0 ]=='i' ?1 :0 }); } vector <Park> item; for (auto & tmp:maps){ auto & v = tmp.se; sort(v.begin (),v.end ()); int k=0 ; for (int i=0 ;i<v.size ();i++){ if (v[i].st){ if (i+1 <v.size ()&&v[i+1 ].st==0 ){ v[k++]=v[i]; v[k++]=v[i+1 ]; i++; } } } v.erase(v.begin ()+k,v.end ()); for (int i=0 ;i<k;i++) item.push_back(v[i]); } vector <string > res; int maxv=0 ; for (int i=0 ;i<item.size ();i+=2 ){ num[item[i].t]++;num[item[i+1 ].t]--; } for (int i=1 ;i<N;i++){ num[i]+=num[i-1 ]; } for (auto tmp:maps){ maxv=max (maxv,get (tmp.se)); } for (auto tmp:maps){ if (get (tmp.se)==maxv) res.push_back({tmp.fi}); } sort(res.begin (),res.end ()); while (k--){ int hh,mm,ss; scanf ("%d:%d:%d" ,&hh,&mm,&ss); int t=hh*3600 +mm*60 +ss; cout <<num[t]<<endl ; } cout <<res[0 ]; for (int i=1 ;i<res.size ();i++) cout <<" " <<res[i]; printf (" %02d:%02d:%02d" ,maxv/3600 ,maxv%3600 /60 ,maxv%60 ); return 0 ; }
🙂1105.Spiral Matrix (25分)(图形打印)🌌
对于选出相差最少的m,n这个要求,我们直接暴力做就好了,枚举到√n,找出可以除尽的最大的一个c(列数),然后用n/c得到r(行数)。
更值得一提的是如何填写这个螺旋矩阵,这是一个十分经典的问题。
首先定义分别定义两个数组dx,dy来表示沿着上下左右移动的偏移量。
由于此题是顺时针方向,所以初始时是向右的方向。
当选定一个方向之后,不断的朝着这个方向走,边走边填写数字,当撞到墙之后(走出最外层边界,或者走到之前走过的位置。),换个方向再继续走下去。
代码
Spiral Matrix 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 #include <iostream> #include <vector> #include <algorithm> #include <cmath> using namespace std ;int main () { int n; cin >>n; vector <int > a; for (int i=0 ;i<n;i++){ int x; scanf ("%d" ,&x); a.push_back(x); } sort(a.begin (),a.end (),greater<int >()); int r=1 ,c=1 ; for (int i=1 ;i*i<=n;i++){ if (n%i==0 ){ c=i; r=n/i; } } vector <vector <int > > v (r,vector <int >(c,0 )) ; int dx[]={0 ,1 ,0 ,-1 },dy[]={1 ,0 ,-1 ,0 }; int k=0 ,dir=0 ; int i=0 ,j=0 ; int x=dx[dir],y=dy[dir]; while (k<n){ while (true ){ v[i][j]=a[k++]; i+=x;j+=y; if (i>=r||i<0 ||j>=c||j<0 ||v[i][j]){ i-=x;j-=y; dir=(dir+1 )%4 ; x=dx[dir],y=dy[dir]; i+=x;j+=y; break ; } } } for (int i=0 ;i<r;i++){ cout <<v[i][0 ]; for (int j=1 ;j<c;j++) cout <<" " <<v[i][j]; puts ("" ); } return 0 ; }
😐1109.Group Photo (25分)🌌
这道题,思路就是首先把整个数组按身高从高到低排序,相同身高的按字典序排序;这样排序之后数组中高的人排在前面,由于我们要先输出后排再输出前排,所以在遍历每列的时候第一列应该是倒数第1排,然后是倒数第2,倒数第3。。。
然后对于如何把人一左一右的放到一排中,这也是一个值得记忆的问题:
思路比较直接,用两个指针分别指向左部和右部,只要两根指针没有超过范围就向指定的位置排人。
代码
Group Photo 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 #include <iostream> #include <algorithm> #include <string> using namespace std ;const int N = 1e4 +10 ;struct Person { string name; int h; bool operator < (const Person &p1) const { if (h!=p1.h) return h>p1.h; return name<p1.name; } }peo[N]; string res[N];int main () { int n,k; cin >>n>>k; for (int i=0 ;i<n;i++)cin >>peo[i].name>>peo[i].h; sort(peo,peo+n); int idx=0 ; for (int i=0 ;i<k;i++){ int len=n/k; if (!i) len+=n%k; for (int r=len/2 +1 ,l=r-1 ;r<=len||l>0 ;l--,r++){ if (r<=len) res[r]=peo[idx++].name; if (l>0 ) res[l]=peo[idx++].name; } cout <<res[1 ]; for (int i=2 ;i<=len;i++) cout <<" " <<res[i]; puts ("" ); } return 0 ; }
😐1051.Pop Sequence (25分)(栈)
这道题,不用费劲心思去思考什么特别复杂的规律什么的,题目已经给出了出栈的顺序,因此我们只用模拟这个过程即可。从1到n不断的入栈元素,当栈顶元素和题目给定的序列的元素相等时,此时则出栈;如果当模拟到无法继续模拟的时候就代表序列不合法:1)超出了栈的容量;2)到最后序列没有模拟完。
代码
Pop Sequence 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include <iostream> #include <algorithm> #include <stack> using namespace std ;int m,n,k;const int N = 1010 ;int a[N];int main () { scanf ("%d%d%d" ,&m,&n,&k); while (k--){ for (int i=1 ;i<=n;i++) scanf ("%d" ,&a[i]); stack <int > s; bool suc=true ; int j=1 ; for (int i=1 ;i<=n;i++){ s.push(i); if (s.size ()>m) suc=false ; while (j<=n&&s.size ()&&s.top()==a[j]){ s.pop(); j++; } } if (j<n) suc=false ; if (!suc) puts ("NO" ); else puts ("YES" ); } return 0 ; }
🙂1055.The World’s Richest (25分)(k路归并)
对于这道题目,我们可以分别存储各个年龄的富翁,把相同年龄的保存在一个链表中(这里用数组模拟就好),然后再分别对每个年龄的富翁按照按worth降序,name升序的规则进行排序。由于这里的年龄最多只有200数值不大【这其实是一个k路归并的问题,本应该用堆来做,但是这里直接暴力遍历也可以过】,因此在处理每次询问的时候,只用依次遍历[amin,amax]年龄区间,比较每个年龄链表头的worth,然后找出worth最大的那个链表头输出,然后删掉该链表头(下面给每个链表开了一个idx数组用来记录遍历到链表的哪个位置了)。
代码
The World's Richest 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 #include <iostream> #include <algorithm> #include <vector> #include <cstring> #include <string> using namespace std ;const int N = 210 ;struct Rich { string name; int age; int worth; bool operator <(Rich &r1)const { if (worth!=r1.worth) return worth > r1.worth; return name < r1.name; } }; vector <Rich> ages[N];int idx[N];int main () { int n,k; scanf ("%d%d" ,&n,&k); char name[10 ]; for (int i=0 ;i<n;i++){ int age,worth; scanf ("%s%d%d" ,name,&age,&worth); ages[age].push_back({name,age,worth}); } for (auto &v:ages) sort(v.begin (),v.end ()); for (int i=1 ;i<=k;i++){ printf ("Case #%d:\n" ,i); memset (idx,0 ,sizeof idx); int m,amin,amax; scanf ("%d%d%d" ,&m,&amin,&amax); bool exist = false ; while (m--){ int t=-1 ; for (int i=amin;i<=amax;i++){ if (idx[i]<ages[i].size ()&&(t==-1 ||ages[t][idx[t]].worth<ages[i][idx[i]].worth)) t = i; } if (t!=-1 ){ Rich p = ages[t][idx[t]]; printf ("%s %d %d\n" ,p.name.c_str(),p.age,p.worth); idx[t]++; exist = true ; } } if (!exist) puts ("None" ); } return 0 ; }
🙂1057.Stack (30分)(栈+堆)🌌
这题比较困难的地方是需要动态输出中位数,针对这个需求,我们可以把数据分为上下两部分,上部分是一个小根堆保存 \(\frac {N} {2}\)个数据;下方是一个大根堆,如果N为偶数,那么保存\(\frac {N} {2}\),如果N是奇数那么保存\(\frac {N} {2} + 1\)个数据。这样我们只需要维护好这两个数据结构,在输出中位数的时候,直接输出下方的大根堆堆顶元素即可。
维护堆 如果上部分数据比下部分数据多,那么就删除上方最小的数然后拿到下面来;如果下部分比上部分的个数+1多,那么就删除下方最大的元素,拿到上面去;由于是平衡二叉树,所以每删除和插入一个元素的时间复杂度为\( O(logn)\)。
由于c++的堆没有提供删除操作,所以对于这题,我们可以使用multiset这个数据结构,其内部实现也是平衡树,如果使用迭代器遍历输出的话,默认从小到大输出。
代码
Stack 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 #include <iostream> #include <algorithm> #include <set> #include <stack> #include <cstring> using namespace std ;stack <int > s;multiset <int > up,down;void adjust () { while (up.size ()>down.size ()){ down.insert(*up.begin ()); up.erase(up.begin ()); } while (down.size ()>up.size ()+1 ){ auto k = down.end (); k--; up.insert(*k); down.erase(k); } } int main () { int n; cin >>n; char op[20 ] ; while (n--){ scanf ("%s" ,op); if (strcmp (op,"Push" )==0 ){ int x; scanf ("%d" ,&x); s.push(x); if (up.empty()|| *up.begin ()>x) down.insert(x); else up.insert(x); adjust(); }else if (strcmp (op,"Pop" )==0 ){ if (s.empty()) puts ("Invalid" ); else { int x = s.top(); s.pop(); auto t=down.end (); t--; if (*t<x) up.erase(up.find (x)); else down.erase(down.find (x)); printf ("%d\n" ,x); adjust(); } }else { if (s.empty()) puts ("Invalid" ); else { auto t = down.end (); t--; printf ("%d\n" ,*t); } } } return 0 ; }
😐1112.Stucked Keyboard (20分)(STL-string)
此题的数据范围比较小,因此可以比较随性的做。首先找到一个第一次访问到的字符之后,就从这个位置开始遍历整个字符串,找出所有由这个字符构成的一段连续区间,看看里面的字符个数是否是k的倍数,如果所有区间都满足条件那么该字符的按键坏掉了。
之后就是替换部分了,遍历刚刚坏掉的字符,每次新建一个字符串p,p由k个当前遍历的字符组成,使用find方法,找出每次p出现的位置,然后再用replace方法替换掉p。
代码
Stucked Keyboard 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 #include <iostream> #include <string> #include <algorithm> #include <map> using namespace std ;map <char ,bool > maps;int main () { int k; string s; cin >>k; getline(cin ,s); getline(cin ,s); string v="" ; for (int i=0 ;i<s.size ();i++){ if (!maps[s[i]]){ maps[s[i]]=true ; char c=s[i]; int suc=true ; int cnt=0 ; for (int l=i;l<=s.size ();l++){ int times=0 ; while (l<=s.size ()&&s[l]==c){ l++; times++; } if (times%k) suc=false ; } if (suc) v+=c; } } cout <<v<<endl ; for (int i=0 ;i<v.size ();i++){ string p (k,v[i]) ; string C (1 ,v[i]) ; int pos=s.find (p); while (s.find (p,pos)!=string ::npos){ pos=s.find (p,pos); s.replace(pos,k,C); pos++; } } cout <<s; return 0 ; }
😐1145.Hashing - Average Search Time (25分)
这题就是模拟一下hash表,在插入的时候把要插入的数字x对hash表的长度s取模得到idx,然后开始迭代,每次把idx加一个k(0<= k< s )的平方,看看对应的位置是否有值,没有的话就直接插入,有的话则继续迭代;如果迭代结束之后还没有找到合适的位置则不可以插入返回-1。
对于查找操作,和上面一样,得到idx之后开始迭代,每次加一个k(0<= k< s )的平方,如果某位置的值等于当前查找数字x的值则返回,否则继续迭代,迭代结束还没有找到返回-1。
代码
Hashing - Average Search Time 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 #include <iostream> using namespace std ;const int N = 1e4 +10 ;int h[N];bool is_prime (int x) { if (x==1 ) return false ; for (int i=2 ;i*i<=x;i++) if (x%i==0 ) return false ; return true ; } int s,n,k;int find (int x,int &cnt) { int idx=x%s; cnt=1 ; for (int i=0 ;i<s;i++,cnt++){ int k=(idx+i*i)%s; if (!h[k]||h[k]==x) return k; } return -1 ; } int main () { scanf ("%d%d%d" ,&s,&n,&k); while (!is_prime(s)) s++; for (int i=0 ;i<n;i++){ int x; scanf ("%d" ,&x); int t; int idx=find (x,t); if (idx==-1 ) printf ("%d cannot be inserted.\n" ,x); else h[idx]=x; } int cnt=0 ; for (int i=0 ;i<k;i++){ int x; scanf ("%d" ,&x); int t; int idx=find (x,t); cnt+=t; } printf ("%.1lf" ,(double ) cnt/k); return 0 ; }