PTA妈妈再也不用担心我被拖库啦!

作者 赵长乐

单位 西安工业大学

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

  1. 不区分字母的大小写,沿用16进制A代表10,B代表11……的规律,将原字符串视为一串36进制的数字
  2. 将字符串平均划为4块,若无法平均划分,保证在前的分块不短于在后的分块,且长度差不超过1。如:长度26的字符串各分块长度为7、7、6、6,长度13的字符串各分块长度为4、3、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!

样例解释:

IronMan的密码为1234qwerasdf,会按照题设方法划分为【123】、【4qw】、【era】、【sdf】并求出哈希值6qfk,而0km6trlhdcwc按此法求出的哈希值也恰为6qfk,因此产生了哈希碰撞。

思路:

照题目一步步操作,主要是哈希判定。

方法:

判定每个区间的大小,求区间和,字符串拼接。因为数字转字符是唯一的,所以不用转。(实际是数据水了。)

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define endl "\n"

ll n;
string s,sx,sy;
map<string,string>mp;

string found(string ss){//查找哈希值 
	ll len=ss.size(),v[10],y=len%4;
	for(ll i = 1 ; i <= 4 ; i ++)
		y >= i ? v[i]=len/4+1 : v[i]=len/4;
	string str;
	ll a=0,b=0,c=0,d=0;
	for(ll i = 0 ; i < ss.size() ; i ++)
		if(i < v[1]){
			ss[i] >= '0' && ss[i] <= '9' ? a+=ss[i]-'0' : a+=ss[i]-'a'+10;
			if(i == v[1]-1)str+=to_string(a%36);
		}else if(i < v[1]+v[2]){
			ss[i] >= '0' && ss[i] <= '9' ? b+=ss[i]-'0' : b+=ss[i]-'a'+10;
			if(i == v[1]+v[2]-1)str+=to_string(b%36);
		}else if(i < v[1]+v[2]+v[3]){
			ss[i] >= '0' && ss[i] <= '9' ? c+=ss[i]-'0' : c+=ss[i]-'a'+10;
			if(i == v[1]+v[2]+v[3]-1)str+=to_string(c%36);
		}else{
			ss[i] >= '0' && ss[i] <= '9' ? d+=ss[i]-'0' : d+=ss[i]-'a'+10;
			if(i == ss.size()-1)str+=to_string(d%36);
		}
	return str;
}

void solve(){
	cin >> n;
	while(n --){
		cin >> s >> sx >> sy;
		for(ll i = 0 ; i < sy.size() ; i ++)sy[i]=tolower(sy[i]);
		if(s == "R"){
			if(mp[sx] != "")cout << "Repeated!" << endl;
			else mp[sx]=sy,cout << "Signed!" << endl;
		}
		if(s == "L"){
			if(mp[sx] == sy)cout << "Success!" << endl;
			else if(found(mp[sx]) == found(sy))cout << "Attention!" << endl;
			else cout << "Failed!" << endl;
		}
	}
	return;
}

int main(){
	ll t=1;//cin >> t;
	while(t --)solve();
	return 0;
}
  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值