202206-1 归一化处理
题目:202206-1
题目分析:
给出了数学上归一化的数学公式,直接按照要求完成即可。
AC代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{int n;cin >> n;double a[n];double sum = 0;for (int i = 0; i < n; i++){cin >> a[i];sum += a[i];}double average = sum / n;double dtotal = 0;for (int i = 0; i < n; i++){dtotal += (a[i] - average) * (a[i] - average);}dtotal /= n;for (int i = 0; i < n; i++){cout << (a[i] - average) / sqrt(dtotal) << endl;}return 0;
}
202206-2 寻宝!大冒险!
为什么我的第一想法是这个???
题目:202206-2
题目分析:
【再更新】
60分代码:
【再更新】
70分代码:
【再更新】
AC代码:
【再更新】
202206-3 角色授权
题目分析:
在学习了数据库之后,对于这道题会更加熟悉。实际上本题就是模拟了数据库对于用户权限的管理。
这道大模拟题主要就是概念很复杂,不容易快速上手理解。
总结如下:
- 用户:主体
- 用户组:用户组里包括很多用户,这些用户有相同的权限
- 角色:指明了一个用户可以执行的操作
- 角色关联:一个用户和一个或多个角色之间的关系,角色关联是一个映射<角色,用户/用户组>
- 待授权行为:包括主体,操作,资源三个部分
判断一个用户能否执行某个操作的过程是:
- 检查所有的角色关联的授权对象清单,如果清单中包含该用户的名称,或者该清单中包含该用户所属的某一个用户组的名称,那么选取该角色关联所关联的角色;
- 对于所有被选取的角色,判断这些角色是否能对该资源执行该操作,如果所有角色都不能执行该操作,那么不能执行该操作;
- 允许执行该操作。
判断一个角色能否对某个资源执行某个操作的过程是:
- 检查该角色的操作清单,如果该角色的操作清单中不包含该操作,且该角色的操作清单中也不包含字符串
*
,那么不能执行该操作; - 检查该角色的资源种类清单,如果该角色的资源种类清单中不包含该资源的种类,且该角色的资源种类清单中也不包含字符串
*
,那么不能执行该操作; - 检查该角色的资源名称清单,如果该角色的资源名称清单中不包含该资源的名称,且该角色的资源名称清单不是空数组,那么不能执行该操作;
- 允许执行该操作。
实际上只要从头到尾执行一遍题目的过程并且不遗漏,就可以拿到大部分的分数。
【注意】一定要按照题目要求由用户->角色再判断是否满足操作、资源类型、资源名。不能直接将角色的权限分配向用户。即不要对于用户A,我知道他有角色BCD,就直接把BCD的操作、资源类型、资源名分别求并,存储在角色A下,这样看上去虽然会简单好多,似乎是优化了。但这样不等价于题目的赋值方式。
反例:
用户A被赋予角色BC
角色B:操作abc、资源类型x、资源名y
角色C:操作def、资源类型z、资源名w
现在询问用户A是否可以操作a,资源类型z,资源名y,这是不可以的。
70分代码:
这个就是从头到尾纯模拟题目的意思,包括存储的结构和执行的操作,都是完全按照题目来的。
具体来说:
前面是读入并存储题目信息。
然后对于每一个被查询的用户(外层循环),先遍历角色链接这个结构体,寻找是否有角色的u数组包含这个用户(这个是单层循环),或者g数组包含这个用户所属的用户组(角色链接一重循环,用户组数组一重循环,这里是两重循环)。现在得到所有包含这个用户的角色,把它们放在一个vector里。
最后遍历这个vector,查看这些角色的所有权限,看看有没有执行被询问的操作、资源种类、资源名的权限。
这个方法实现的瓶颈在于外层循环内的两重循环,最坏的情况下,外层循环q,内层循环m*ng,就需要q*m*ng,5000*500*400,这能达到10^9,这已经是超时了,一般10^8对应1s的数量级,这都需要10s了。因此这个方法只能拿70%数据点。
下面是代码(完全由本人完成):
// -*- coding:utf-8 -*-// File : 202206-3.cpp
// Time : 2024/03/26
// Author : wolf#include <iostream>
#include <vector>
const int N = 501;using namespace std;// 存储角色信息
struct character
{string name;int nv;vector<string> op;int no;vector<string> rtype;int nn;vector<string> rname;
};// 存储角色与用户/用户组的链接
struct character_link
{string cname;struct character ch;vector<string> u;vector<string> g;
};vector<character> c;
vector<character_link> c_link;int main()
{// 关闭同步ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);// 即使关闭同步,该算法还是会超时,这是算法本身的局限int n, m, q;cin >> n >> m >> q;for (int i = 0; i < n; i++){struct character ctemp;cin >> ctemp.name;cin >> ctemp.nv;for (int j = 0; j < ctemp.nv; j++){string temp;cin >> temp;ctemp.op.push_back(temp);}cin >> ctemp.no;for (int j = 0; j < ctemp.no; j++){string temp;cin >> temp;ctemp.rtype.push_back(temp);}cin >> ctemp.nn;for (int j = 0; j < ctemp.nn; j++){string temp;cin >> temp;ctemp.rname.push_back(temp);}c.push_back(ctemp);}for (int i = 0; i < m; i++){struct character_link cltemp;cin >> cltemp.cname;for (unsigned int j = 0; j < c.size(); j++){if (cltemp.cname == c[j].name){cltemp.ch = c[j];}}int ns;cin >> ns;for (int j = 0; j < ns; j++){string ug, ugname;cin >> ug >> ugname;if (ug == "u"){cltemp.u.push_back(ugname);}else if (ug == "g"){cltemp.g.push_back(ugname);}else{cout << "error" << endl;}}c_link.push_back(cltemp);}for (int i = 0; i < q; i++){string query_user;cin >> query_user;int ng;vector<string> query_ugroup;cin >> ng;for (int j = 0; j < ng; j++){string uboxtemp;cin >> uboxtemp;query_ugroup.push_back(uboxtemp);}string query_op, query_rtype, query_rname;cin >> query_op >> query_rtype >> query_rname;// excuteint ans = 0; // default okvector<character> target_c;for (unsigned int j = 0; j < c_link.size(); j++){for (unsigned int k = 0; k < c_link[j].u.size(); k++){if (query_user == c_link[j].u[k]){target_c.push_back(c_link[j].ch);}}for (unsigned int k = 0; k < c_link[j].g.size(); k++){for (unsigned int t = 0; t < query_ugroup.size(); t++){if (query_ugroup[t] == c_link[j].g[k]){target_c.push_back(c_link[j].ch);}}}}for (unsigned int j = 0; j < target_c.size(); j++){character cnow = target_c[j];// cout << cnow.name << endl;int flag1 = false, flag2 = false, flag3 = false; // default nofor (unsigned int k = 0; k < cnow.op.size(); k++){// cout << query_op << " " << cnow.op[k] << endl;if (query_op == cnow.op[k] || cnow.op[k] == "*"){flag1 = true;break;}}if (flag1 == false)continue;for (unsigned int k = 0; k < cnow.rtype.size(); k++){// cout << query_op << " " << cnow.op[k] << endl;if (query_rtype == cnow.rtype[k] || cnow.rtype[k] == "*"){flag2 = true;break;}}if (flag2 == false)continue;if (cnow.rname.size() == 0)flag3 = true;else{for (unsigned int k = 0; k < cnow.rname.size(); k++){if (query_rname == cnow.rname[k]){flag3 = true;break;}}}if (flag3 == false)continue;// successif (flag1 == true && flag2 == true && flag3 == true){ans = 1;break;}}cout << ans << endl;}return 0;
}
AC代码:
基于上述的分析,我们可以发现瓶颈在于从角色链接去回溯用户对应的角色。如果我能从一开始就知道每一个用户对应哪些角色,是不是就能节省很多时间呢?c++真有这么神奇的数据结构。
使用STL库中的<map>,我们做了一些小改动:
建立<角色名称 - 角色本体>映射,在找到角色名称之后,可以使用find()直接对应到角色本体。
使用多元map保存用户,用户组和角色之间的关联关系,同样在拿到用户之后,使用find()就可以找到角色,不需要从角色的视角去遍历,使用多元map是因为对于一个用户键,可能有多个角色与之相对应,即一个用户被赋予了多个角色。
这里能显著提升效率,是因为<algorithm>中的find(),使用树结构查找,时间复杂度是O(logn),显著大于从角色视角去for循环再验证用户/用户组在不在里面,这样是O(n)。
主要发现还是大量运用了STL库的“黑科技”。
【有参考】https://blog.csdn.net/Andy_Xie007/article/details/133800502
// -*- coding:utf-8 -*-// File : 202206-3.cpp
// Time : 2024/03/26
// Author : wolf#include <algorithm>
#include <iostream>
#include <map>
#include <set>
#include <unordered_set>
#include <vector>
// 有参考https://blog.csdn.net/Andy_Xie007/article/details/133800502
const int N = 501;using namespace std;
struct character
{string name;set<string> op; // 操作set<string> rtype; // 资源种类set<string> rname; // 资源名称// 使用unordered_set会加快速度:2.984s -> 2.39s// unordered_set<string> op; / 操作// unordered_set<string> rtype; // 资源种类// unordered_set<string> rname; // 资源名称
};map<string, character> c; // 角色名称 - 角色本体映射
// 使用find进行检索O(n)时间复杂度,比数组快// 判断cnow角色是否有对(query_op,query_rtype,query_rname)的访问权限
// 使用&传递地址而不是参复制,节省大量时间,否则超时
int check(const character &cnow, const string &query_op, const string &query_rtype, const string &query_rname)
{if (cnow.op.count(query_op) == 0 && cnow.op.count("*") == 0)return 0;if (cnow.rtype.count(query_rtype) == 0 && cnow.rtype.count("*") == 0)return 0;if (cnow.rname.count(query_rname) == 0 && !cnow.rname.empty())return 0;return 1;
}int main()
{// 关闭同步ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);// 加了以上三句话,由90->100int n, m, q;cin >> n >> m >> q;for (int i = 0; i < n; i++){struct character ctemp;string temp;int nv, no, nn;cin >> ctemp.name;cin >> nv;for (int j = 0; j < nv; j++){cin >> temp;ctemp.op.insert(temp);}cin >> no;for (int j = 0; j < no; j++){cin >> temp;ctemp.rtype.insert(temp);}cin >> nn;for (int j = 0; j < nn; j++){cin >> temp;ctemp.rname.insert(temp);}c.insert(make_pair(ctemp.name, ctemp));}// 使用多元map保存用户,用户组和角色之间的关联关系,查找会很快multimap<string, string> relative_u; // user - charactermultimap<string, string> relative_g; // group - characterfor (int i = 0; i < m; i++){string cname;cin >> cname;int ns;cin >> ns;for (int j = 0; j < ns; j++){string ug, ugname;cin >> ug >> ugname;if (ug == "u"){relative_u.insert(make_pair(ugname, cname));}else if (ug == "g"){relative_g.insert(make_pair(ugname, cname));}else{cout << "error" << endl;}}}for (int i = 0; i < q; i++){string query_user;cin >> query_user;int ng;cin >> ng;vector<string> query_ugroup;for (int j = 0; j < ng; j++){string uboxtemp;cin >> uboxtemp;query_ugroup.push_back(uboxtemp);}string query_op, query_rtype, query_rname;cin >> query_op >> query_rtype >> query_rname;// excuteint flag = 0;vector<character> target_c;// upair<multimap<string, string>::iterator, multimap<string, string>::iterator> range_u = relative_u.equal_range(query_user);// auto range_u = relative_u.equal_range(query_user);for (auto it = range_u.first; it != range_u.second; it++){if (check(c.find(it->second)->second, query_op, query_rtype, query_rname)){flag = 1;break;}}if (flag == 1){cout << 1 << endl;continue;}// gfor (unsigned int j = 0; j < query_ugroup.size(); j++){pair<multimap<string, string>::iterator, multimap<string, string>::iterator> range_g = relative_g.equal_range(query_ugroup[j]);// auto range_g = relative_g.equal_range(query_ugroup[j]);for (auto it = range_g.first; it != range_g.second; it++){if (check(c.find(it->second)->second, query_op, query_rtype, query_rname)){flag = 1;break;}}if (flag == 1){break;}}if (flag == 1){cout << 1 << endl;continue;}cout << 0 << endl;}return 0;
}