A - ZJM 与霍格沃兹(必做)
问题描述
ZJM 为了准备霍格沃兹的期末考试,决心背魔咒词典,一举拿下咒语翻译题
题库格式:[魔咒] 对应功能
背完题库后,ZJM 开始刷题,现共有 N 道题,每道题给出一个字符串,可能是 [魔咒],也可能是对应功能
ZJM 需要识别这个题目给出的是 [魔咒] 还是对应功能,并写出转换的结果,如果在魔咒词典里找不到,输出 “what?”
Input
首先列出魔咒词典中不超过100000条不同的咒语,每条格式为:
[魔咒] 对应功能
其中“魔咒”和“对应功能”分别为长度不超过20和80的字符串,字符串中保证不包含字符“[”和“]”,且“]”和后面的字符串之间有且仅有一个空格。魔咒词典最后一行以“@END@”结束,这一行不属于词典中的词条。
词典之后的一行包含正整数N(<=1000),随后是N个测试用例。每个测试用例占一行,或者给出“[魔咒]”,或者给出“对应功能”。
Output
每个测试用例的输出占一行,输出魔咒对应的功能,或者功能对应的魔咒。如果在词典中查不到,就输出“what?”
思路
使用hash。
将魔咒和对应功能分别计算出hash值,然后存储到两个数组中,一个按魔咒的hash值大小存储,一个按对应功能的hash值大小存储,查找时二分查找。
存储单独放在一个string数组中,存两次内存会爆,所以之前的两个数组中还要有对应字符串的序号。
代码
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
struct node
{
long long x,y;
int l,num;
bool operator <(const node &a)
{
return x<a.x;
}
};
node a[100010],b[100010];
string ss[100010];
int main()
{
int tot,n,l,r,mid,ans;
long long x;
string s;
getline(cin,s);
tot=0;
while (s[0]!='@')
{
a[tot].x=0;
a[tot].y=0;
a[tot].num=tot;
b[tot].num=tot;
ss[tot]=s;
for (int i=1;i<s.length();i++)
if (s[i]==']')
{
l=i;
break;
}
a[tot].l=l;
b[tot].l=l;
for (int i=1;i<l;i++)
a[tot].x=(a[tot].x*17+s[i])%1000000007;
for (int i=l+2;i<s.length();i++)
a[tot].y=(a[tot].y*17+s[i])%1000000007;
b[tot].x=a[tot].y;
b[tot].y=a[tot].x;
tot++;
getline(cin,s);
}
sort(a,a+tot);
sort(b,b+tot);
cin>>n;
getline(cin,s);
while (n--)
{
getline(cin,s);
x=0;
if (s[0]=='[')
{
for (int i=1;i<s.length()-1;i++)
x=(x*17+s[i])%1000000007;
l=0; r=tot;
while (l<=r)
{
mid=(l+r)/2;
if (a[mid].x==x)
{
ans=mid;
break;
}
if (a[mid].x<x)
l=mid+1;
else
r=mid-1;
}
if (a[ans].x==x)
{
for (int i=a[ans].l+2;i<ss[a[ans].num].length();i++)
cout<<ss[a[ans].num][i];
cout<<endl;
}
else
cout<<"what?"<<endl;
}
else
{
for (int i=0;i<s.length();i++)
x=(x*17+s[i])%1000000007;
l=0; r=tot;
while (l<=r)
{
mid=(l+r)/2;
if (b[mid].x==x)
{
ans=mid;
break;
}
if (b[mid].x<x)
l=mid+1;
else
r=mid-1;
}
if (b[ans].x==x)
{
for (int i=1;i<b[ans].l;i++)
cout<<ss[b[ans].num][i];
cout<<endl;
}
else
cout<<"what?"<<endl;
}
}
return 0;
}