7-3 账户安全预警
拼题 A 系统为提高用户账户的安全性,打算开发一个自动安全预警的功能。对每个账户的每次登录,系统会记录其登录的 IP 地址。每隔一段时间,系统将统计每个账户从多少不同的 IP 地址分别登录了多少次。如果某个账户的登录 IP 超过了 Tip 种,并且登录过于频繁,超过了 Tlogin次,则会自动向管理员发出警报。 下面就请你实现这个预警功能。
题目描述
输入首先在第一行中给出三个正整数:N(≤104)为登录记录的条数;TIP 和 Tlogin,定义如题面中所描述,均不超过 100。
随后 N 行,每行格式为:
账户邮箱 IP地址
其中 账户邮箱
为长度不超过 40 的、不包含空格的非空字符串;IP地址
为形如 xxx.xxx.xxx.xxx
的合法 IP 地址。
输出格式
按照登录所用不同 IP 的数量的非递增顺序,输出每个预警账户的信息。格式为:
账户邮箱 IP1 登录次数 IP2 登录次数 ……
其中 IP 按登录次数的非递增顺序输出,如有并列,则按 IP 的递增字典序输出。此外,对所用不同 IP 的数量并列的用户,按其账户邮箱的递增字典序输出。
另一方面,即使没有账户达到预警线,也输出登录所用不同 IP 的数量最多的一批账户的信息。
输入样例1
24 3 4 daohaole@qq.com 218.109.231.189 1jiadelaolao@163.com 112.192.203.187 chenyuelaolao@zju.edu.cn 112.18.235.143 jiadelaolao@163.com 112.192.203.187 chenyuelaolao@zju.edu.cn 113.18.235.143 jiadelaolao@163.com 111.192.203.187 daohaole@qq.com 218.109.231.189 chenyuelaolao@zju.edu.cn 111.18.235.143 1jiadelaolao@163.com 115.192.203.187 daohaole@qq.com 113.189.58.141 1jiadelaolao@163.com 111.192.203.187 daohaole@qq.com 112.18.58.145 1jiadelaolao@163.com 114.192.203.187 chenyuelaolao@zju.edu.cn 112.18.235.143 daohaole@qq.com 123.89.158.214 chenyuelaolao@zju.edu.cn 112.18.235.143 youdaohaole@qq.com 218.109.231.189 jiadelaolao@163.com 113.192.203.187 youdaohaole@qq.com 218.109.231.189 jiadelaolao@163.com 114.192.203.187 youdaohaole@qq.com 113.189.58.141 youdaohaole@qq.com 123.89.158.214 1jiadelaolao@163.com 113.192.203.187 youdaohaole@qq.com 112.18.58.145
输出样例1
1jiadelaolao@163.com 111.192.203.187 1 112.192.203.187 1 113.192.203.187 1 114.192.203.187 1 115.192.203.187 1 daohaole@qq.com 218.109.231.189 2 112.18.58.145 1 113.189.58.141 1 123.89.158.214 1 youdaohaole@qq.com 218.109.231.189 2 112.18.58.145 1 113.189.58.141 1 123.89.158.214 1
输入样例2
24 5 8 daohaole@qq.com 218.109.231.189 1jiadelaolao@163.com 112.192.203.187 chenyuelaolao@zju.edu.cn 112.18.235.143 jiadelaolao@163.com 112.192.203.187 chenyuelaolao@zju.edu.cn 113.18.235.143 jiadelaolao@163.com 111.192.203.187 daohaole@qq.com 218.109.231.189 chenyuelaolao@zju.edu.cn 111.18.235.143 1jiadelaolao@163.com 115.192.203.187 daohaole@qq.com 113.189.58.141 1jiadelaolao@163.com 111.192.203.187 daohaole@qq.com 112.18.58.145 1jiadelaolao@163.com 114.192.203.187 chenyuelaolao@zju.edu.cn 112.18.235.143 daohaole@qq.com 123.89.158.214 chenyuelaolao@zju.edu.cn 112.18.235.143 youdaohaole@qq.com 218.109.231.189 jiadelaolao@163.com 113.192.203.187 youdaohaole@qq.com 218.109.231.189 jiadelaolao@163.com 114.192.203.187 youdaohaole@qq.com 113.189.58.141 youdaohaole@qq.com 123.89.158.214 1jiadelaolao@163.com 113.192.203.187 youdaohaole@qq.com 112.18.58.145
输出样例2
1jiadelaolao@163.com 111.192.203.187 1 112.192.203.187 1 113.192.203.187 1 114.192.203.187 1 115.192.203.187 1
题解
分析题目可得,我们需要找到邮箱访问的ip种数超过Tip种,并且邮箱总共访问的次数超过了Tlogin次的账户,并打印输出。注意,输出格式非常的有讲究,邮箱先按ip种类数排序(降序),(若ip种数相同)再按字典序(递增)输出,每个邮箱的ip地址按访问次数降序排序,(若访问次数相同)再按字典序增序输出。如果没有需要发出预警账户,那么,输出访问ip种数最大的邮箱(注意!!!可能不止一个!!)。
为了方便排序,我们设计两个结构体如下:
struct IP{
string ip; //ip名字
int time; //ip访问次数
};//该结构体为IP结构体
struct Email{
string email; //Email的名字
int num; //ip种数
};//该结构体为Email结构体
排序(仿函数):
bool cmp(IP a,IP b){
return a.time!=b.time?a.time > b.time : a.ip<b.ip;
}
bool cmp2(Email a,Email b){
return a.num!=b.num?a.num > b.num : a.email<b.email;
}
输入:
int n,ip,login;//总访问次数,Tip,Tlogin
cin >> n >> ip >> login;
map<string,set<string> > ipx; //记录原本的所有信息(邮箱名称,set<IP名称>)
map<pair<string,string>,int> loginx; //记录对应邮箱中的某个IP访问次数({邮箱名,ip名},访问次数)
map<string,int> ttt; //记录对应邮箱的总访问数
int max = 0; //邮箱中的最大不同ip种数
for(int i = 0;i < n ;i++) {
string a,b;
cin >> a >> b;
ipx[a].insert(b);
ttt[a]++;
loginx[{a,b}] += 1;
if(max < ipx[a].size()){
max = ipx[a].size();
}
}
装入结构体、排序:
map<string,set<string> >::iterator itxxx;
vector<Email> ben; //用vector记录所有输入的邮箱
for(itxxx = ipx.begin();itxxx!=ipx.end();itxxx++){
Email y;
y.email = itxxx->first;
y.num = ipx[itxxx->first].size();
ben.push_back(y);
}
sort(ben.begin(),ben.end(),cmp2);
筛选:
vector<Email> result; //记录需要发预警的邮箱名字
for(int i = 0;i < ben.size();i++){
if(ipx[ben[i].email].size() > ip && ttt[ben[i].email] > login)
result.push_back(ben[i]);
}
当没有需要发出预警的邮箱时:
if(result.size() == 0) {
for(int i = 0;i<ben.size();i++){
if(ipx[ben[i].email].size() == max){ //判断一下是否是ip种数最大
result.push_back(ben[i]); //直接加入结果集
}
}
}
当有需要发出预警时:
for(int i = 0;i < result.size();i++) { //将结果集输出
cout << result[i].email << endl;
set<string>::iterator itx;
vector<IP> sortt; //将邮箱中的ip放入容器中排序
for(itx = ipx[result[i].email].begin();itx!=ipx[result[i].email].end();itx++){
IP x;
x.ip=*itx;
x.time = loginx[{result[i].email,*itx}];
sortt.push_back(x);
}
sort(sortt.begin(),sortt.end(),cmp);
for(int i = 0;i < sortt.size();i++) {
cout << sortt[i].ip << " " << sortt[i].time <<endl;
}
}
本题完成
技术点
熟练掌握STL中的容器特性和使用。模拟。
1.vector
动态数组。本题知识点如下:
vector.push_back(); vector.size(); //遍历可以直接使用下标访问
2.set
集合,不可重复出现。
set.insert(); set.begin(); set.end(); //遍历使用迭代器
3.map
映射。
//遍历使用迭代器