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;
//}