PTA 妈妈再也不用担心我被拖库啦! (25分)

it2025-03-15  27

PTA 妈妈再也不用担心我被拖库啦! (25分)

众所周知,互联网时代以来各大公司被“脱裤”的历史是一部五彩缤纷(误)的血泪史,给各大厂商造成了极大的经济损失。更为重要的是,由于有些用户在多个网站使用相同的用户名、密码,一旦一家网站被拖库,用户往往会遭受全方位的损失。为避免此情况,良心企业一般只在数据库中存储用户密码的哈希值——也就是根据特定规则产生的散列值,无法由此倒推出原密码。但这种方法也有一个缺点,即输入不同的密码有极小概率会得到一样的哈希值(我们称之为碰撞),从而被系统认定密码正确!现在你所在的公司采取如下方法产生密码字符串(长度至少为8,只包含大小写字母和数字)的哈希值:

不区分字母的大小写,沿用16进制A代表10,B代表11……的规律,将原字符串视为一串36进制的数字将字符串平均划为4块,若无法平均划分,保证在前的分块不短于在后的分块,且长度差不超过1。如:长度26的字符串各分块长度为7、7、6、6,长度13的字符串各分块长度为4、3、3、3将每块的数字加和,取其个位数,四块取出的四个36进制数字顺次连接,得到一个四位36进制数字,即为该密码字符串的哈希值。

然而由于这种方式过于睿智,使得碰撞的几率奇高,你的任务就是为公司防范风险,在碰撞发生的时候给予示警!

输入格式: 第一行一个整数N(N<1000),为操作的个数。 以下N行,每行一个字符、两个字符串(length<100),中间均以空格分隔。字符代表操作类型,两个字符串代表用户名和密码。

当字符为L时,代表以该用户名密码尝试登录;

当字符为R时,代表尝试注册这组用户名、密码,若注册成功则记录在案。

输出格式: N行,对于每一个L(登录操作),若密码正确,则输出一行“Success!”;

若密码错误或用户不存在,则输出一行“Failed!”;

若密码错误但会通过哈希检测而被放行,则输出一行“Attention!”。

对于每一个R(注册操作),若已存在该用户名,则输出一行“Repeated!”;

否则注册成功,输出一行“Signed!”。

以上输出均不包括引号。 输入样例: 5 R IronMan 1234qwerasdf R IronMan whejrdfs345 L IronMan 1234qwerasdf L IronMan whejrdfs345 L IronMan 0km6trlhdcwc 输出样例: Signed! Repeated! Success! Failed! Attention!

额额这道题写了快一个小时,细节问题很多。说一下个人思路:

将字符串分为四块方法:字符串长度为L,则至少每块有L/4个字符,L对4求余值为y,则前y个字串的长度为L/4+1。很明显y值只有0、1、2、3这四种取值可能。对字串的哈希值求解方法:定义一个int变量sum,从左到右遍历字串,若str[i]为数字字符,则sum+=str[i]-‘0’(即转为int型加给sum);若str[i]为字母,(我这里将所有大写字母转为小写字母来进行计算),sum+=str[i]-‘a’+10;也就是说,将字符类型值转为相应int类型值。算出和之后对36求余,余值小于10,即为对应的字符1-9;余值大于10,即为sum-10+'a’对应的小写字母。对于注册和登录方法:本人使用了map来存储已注册账号所对应的密码及密码的哈希值。即map<string,pair<string,string> > mp; AC代码: #include<iostream> #include<string> #include<map> using namespace std; struct Node{ string c; //操作符记录 string zh; //账号 string mm; //密码 string hx; //密码所对应的哈希值 }; int n; Node node[1005]; map<string,pair<string,string> > mp;//已注册账号信息存储,map中第一个参数为账号,第二个参数为pair型,pair中第一个参数为密码,第二个参数为密码对应的哈希值。 char small_Hash(string str){ //计算字串的哈希值,返回一个字符char int sum=0; for(int i=0;i<str.length();i++){ if(str[i]>='A'&&str[i]<='Z') str[i]=str[i]|32; if(str[i]>='0'&&str[i]<='9'){ sum+=str[i]-'0'; }else{ sum+=str[i]-'a'+10; } } //cout<<"sum:"<<sum<<endl; sum=sum%36; if(sum<10) return sum+'0'; else return sum-10+'a'; } string Hash(string str){ //计算密码的哈希值,返回四位字符串 string hx="0000"; int l=str.length(); int index[5]={0}; for(int i=0;i<l%4;i++){ index[i]++; } int j=0; for(int i=0;i<4;i++){ index[i]+=l/4; string str1=str.substr(j,index[i]); //cout<<"str1:"<<i<<":"<<str1<<endl; j+=index[i]; char h=small_Hash(str1); hx[i]=h; } return hx; } int main(void){ cin>>n; for(int i=0;i<n;i++){ cin>>node[i].c>>node[i].zh>>node[i].mm; node[i].hx=Hash(node[i].mm); //cout<<node[i].hx<<endl; if(node[i].c=="R"){ if(mp.find(node[i].zh)!=mp.end())cout<<"Repeated!"<<endl; else { mp[node[i].zh].first=node[i].mm; mp[node[i].zh].second=node[i].hx; cout<<"Signed!"<<endl; } }else if(node[i].c=="L"){ if(mp.find(node[i].zh)==mp.end()){ cout<<"Failed!"<<endl; }else{ if(mp.find(node[i].zh)->second.first==node[i].mm) cout<<"Success!"<<endl; else{ //cout<<mp.find(node[i].zh)->second.second<<" "<<node[i].hx<<endl; if(mp.find(node[i].zh)->second.second==node[i].hx)cout<<"Attention!"<<endl; else cout<<"Failed!"<<endl; } } } } return 0; } //int main(void){ //检验字串哈希值计算 // string str="sdf"; // cout<<small_Hash(str); // return 0; //}
最新回复(0)