[模拟][stl]账户安全预警 2022RoboCom决赛C

166 阅读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

题意:

给出n条登录记录,每个记录由登录邮箱和登录ip组成,同时给出两参数k1和k2,当某邮箱登录次数超过k1且不同登录ip超过k2就将该登录邮箱标记为预警账户,按照题目要求输出所有预警账户,每个预警账户还要输出各登录ip及其出现次数,如果不存在预警账户,那么就输出不同ip最多的那批账户信息。

分析:

其实就是一个比较复杂的模拟题,如果借助stl来实现就会比较容易,首先用一个map<string, vector>保存下来每个邮箱的全部登录ip,之后遍历该map,对于每一个邮箱的登录ip进行合并,这里可以再开一个map<string, vector<pair<string, int>>>,其中vector<pair<string, int>>就保存了该邮箱不同种类的ip以及其出现次数,最后按照题目要求分别对邮箱和相应ip进行排序即可。

具体代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
#include <set>
#include <vector> 
#include <unordered_map>
using namespace std;

unordered_map<string, vector<string>> mp;
unordered_map<string, vector<pair<string, int>>> mp2;

bool cmp(string x, string y){
	if(mp2[x].size() != mp2[y].size())
		return mp2[x].size() > mp2[y].size();
	return x < y;
}

bool cmp2(pair<string, int> x, pair<string, int> y){
	if(x.second != y.second)
		return x.second > y.second;
	return x.first < y.first;
}

signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	int n, k1, k2;
	cin >> n >> k1 >> k2;
	for(int i = 1; i <= n; i++){
		string s1, s2;
		cin >> s1 >> s2;
		mp[s1].push_back(s2);
	}
	vector<string> res;
	for(unordered_map<string, vector<string>>::iterator it = mp.begin(); it != mp.end(); it++){
		unordered_map<string, int> a;
		for(int i = 0; i < (it->second).size(); i++){
			string s = (it->second)[i];
			a[s]++;
		}
		for(unordered_map<string, int>::iterator i = a.begin(); i != a.end(); i++)
			mp2[it->first].push_back(make_pair(i->first, a[i->first]));
		if(a.size() > k1 && (it->second).size() > k2)
			res.push_back(it->first);
	}
	sort(res.begin(), res.end(), cmp);
	for(int i = 0; i < res.size(); i++){
		cout << res[i] << endl;
		vector<pair<string, int>> ip = mp2[res[i]];
		sort(ip.begin(), ip.end(), cmp2);
		for(int j = 0; j < ip.size(); j++)
			cout << ip[j].first << " " << ip[j].second << endl;
	}
	if(res.size() == 0){
		int mx = 0;
		for(unordered_map<string, vector<pair<string, int>>>::iterator it = mp2.begin(); it != mp2.end(); it++){
			mx = max(mx, (int)(it->second).size());
		}
		for(unordered_map<string, vector<pair<string, int>>>::iterator it = mp2.begin(); it != mp2.end(); it++){
			if((it->second).size() == mx)
				res.push_back(it->first);
		}
		sort(res.begin(), res.end(), cmp);
		for(int i = 0; i < res.size(); i++){
			cout << res[i] << endl;
			vector<pair<string, int>> ip = mp2[res[i]];
			sort(ip.begin(), ip.end(), cmp2);
			for(int j = 0; j < ip.size(); j++)
				cout << ip[j].first << " " << ip[j].second << endl;
		}
	}
    return 0;
}