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

  • Post author:
  • Post category:其他




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



版权声明:本文为yan936462437原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。