【c/c++算法刷题笔记】—— 1.33 CCF 打卡20(201612)

【前言】OJ:CCF-CSP 模拟考试

1 201612-1 中间数

题目描述

问题描述
  在一个整数序列a1, a2, …, an中,如果存在某个数,大于它的整数数量等于小于它的整数数量,则称其为中间数。在一个序列中,可能存在多个下标不相同的中间数,这些中间数的值是相同的。
  给定一个整数序列,请找出这个整数序列的中间数的值。
  
输入格式
  输入的第一行包含了一个整数n,表示整数序列中数的个数。
  第二行包含n个正整数,依次表示a1, a2, …, an。
  
输出格式
  如果约定序列的中间数存在,则输出中间数的值,否则输出-1表示不存在中间数。

样例

样例输入
6
2 6 5 6 3 5
样例输出
5
样例说明
  比5小的数有2个,比5大的数也有2个。
  
样例输入
4
3 4 6 7
样例输出
-1
样例说明
  在序列中的4个数都不满足中间数的定义。
  
样例输入
5
3 4 6 6 7
样例输出
-1
样例说明
  在序列中的5个数都不满足中间数的定义。
  
评测用例规模与约定
  对于所有评测用例,1 ≤ n ≤ 1000,1 ≤ ai ≤ 1000。

笔记

见代码

代码
#include<iostream>
#include<algorithm>
using namespace std;

int main(){
	int n;
	cin>>n;
	int num[n];
	for(int i=0;i<n;i++) cin>>num[i];
	sort(num,num+n);
	int mi=0,ma=0;
	for(int i=0;i<n;i++){
		if(num[i]<num[n/2]) mi++;
		else if(num[i]>num[n/2]) ma++;
	}
	if(mi==ma){
		if(n%2==0 && num[n/2]!=num[n/2-1]) cout<<-1;
		else cout<<num[n/2];
	}
	else cout<<-1;
	return 0;
}

2 201612-2 工资计算

题目描述

问题描述
  小明的公司每个月给小明发工资,而小明拿到的工资为交完个人所得税之后的工资。假设他一个月的税前工资(扣除五险一金后、未扣税前的工资)为S元,则他应交的个人所得税按如下公式计算:
  1) 个人所得税起征点为3500元,若S不超过3500,则不交税,3500元以上的部分才计算个人所得税,令A=S-3500元;
  2) A中不超过1500元的部分,税率3%;
  3) A中超过1500元未超过4500元的部分,税率10%;
  4) A中超过4500元未超过9000元的部分,税率20%;
  5) A中超过9000元未超过35000元的部分,税率25%;
  6) A中超过35000元未超过55000元的部分,税率30%;
  7) A中超过55000元未超过80000元的部分,税率35%;
  8) A中超过80000元的部分,税率45%;
  例如,如果小明的税前工资为10000元,则A=10000-3500=6500元,其中不超过1500元部分应缴税1500×3%=45元,超过1500元不超过4500元部分应缴税(4500-1500)×10%=300元,超过4500元部分应缴税(6500-4500)×20%=400元。总共缴税745元,税后所得为9255元。
  已知小明这个月税后所得为T元,请问他的税前工资S是多少元。
  
输入格式
  输入的第一行包含一个整数T,表示小明的税后所得。所有评测数据保证小明的税前工资为一个整百的数。
  
输出格式
  输出一个整数S,表示小明的税前工资。

样例

样例输入
9255

样例输出
10000

评测用例规模与约定
  对于所有评测用例,1 ≤ T ≤ 100000。

笔记

见代码注释

代码

/*
	工资计算 
	
	3500保底 
	if t<3500 :t , a税后,A税前 
	else{//a=t-3500 是扣过税的部分 
		a>1500*97% ? a-=1500*97% ;ans=+1500; 
		a>3000*90% ? a-=3000*90%;ans+=3000;
		a>4500*80% ? ......
		a>26000*75% ?......
		a>20000*70% ?......
		a>25000*65% ? ......
		ans += a/55%;
	}
*/ 
#include<iostream>
using namespace std;

int t,ans=0,a;
bool total(int pri,double pect){
	if(a>pri*pect) {
		ans+=pri;
		a-=pri*pect;
		return true;
	}
	else ans+=a/pect;
	return false;
}

int main(){
	cin>>t;
	if(t<=3500) ans=t;
	else{
		ans+=3500;
		a=t-3500;
		if(total(1500,0.97))
		if(total(3000,0.90))
		if(total(4500,0.80))
		if(total(26000,0.75))
		if(total(20000,0.70))
		if(total(25000,0.65))
		if(a) ans+=a/0.55;
	}
	cout<<ans;
	return 0;
	
}

3 201612-3 权限查询

题目描述

问题描述
  授权 (authorization) 是各类业务系统不可缺少的组成部分,系统用户通过授权机制获得系统中各个模块的操作权限。
  本题中的授权机制是这样设计的:每位用户具有若干角色,每种角色具有若干权限。例如,用户 david 具有 manager 角色,manager 角色有 crm:2 权限,则用户 david 具有 crm:2 权限,也就是 crm 类权限的第 2 等级的权限。
  具体地,用户名和角色名称都是由小写字母组成的字符串,长度不超过 32。权限分为分等级权限和不分等级权限两大类。分等级权限由权限类名和权限等级构成,中间用冒号“:”分隔。其中权限类名也是由小写字母组成的字符串,长度不超过 32。权限等级是一位数字,从 0 到 9,数字越大表示权限等级越高。系统规定如果用户具有某类某一等级的权限,那么他也将自动具有该类更低等级的权限。例如在上面的例子中,除 crm:2 外,用户 david 也具有 crm:1 和 crm:0 权限。不分等级权限在描述权限时只有权限类名,没有权限等级(也没有用于分隔的冒号)。
  给出系统中用户、角色和权限的描述信息,你的程序需要回答多个关于用户和权限的查询。查询可分为以下几类:
  * 不分等级权限的查询:如果权限本身是不分等级的,则查询时不指定等级,返回是否具有该权限;
  * 分等级权限的带等级查询:如果权限本身分等级,查询也带等级,则返回是否具有该类的该等级权限;
  * 分等级权限的不带等级查询:如果权限本身分等级,查询不带等级,则返回具有该类权限的等级;如果不具有该类的任何等级权限,则返回“否”。
输入格式
  输入第一行是一个正整数 p,表示不同的权限类别的数量。紧接着的 p 行被称为 P 段,每行一个字符串,描述各个权限。对于分等级权限,格式为 :,其中 是权限类名, 是该类权限的最高等级。对于不分等级权限,字符串只包含权限类名。
  接下来一行是一个正整数 r,表示不同的角色数量。紧接着的 r 行被称为 R 段,每行描述一种角色,格式为
   <privilege 1> <privilege 2> …
  其中 是角色名称, 表示该角色具有多少种权限。后面 个字符串描述该角色具有的权限,格式同 P 段。
  接下来一行是一个正整数 u,表示用户数量。紧接着的 u 行被称为 U 段,每行描述一个用户,格式为
   <role 1> <role 2> …
  其中 是用户名, 表示该用户具有多少种角色。后面 个字符串描述该用户具有的角色。
  接下来一行是一个正整数 q,表示权限查询的数量。紧接着的 q 行被称为 Q 段,每行描述一个授权查询,格式为 ,表示查询用户 是否具有 权限。如果查询的权限是分等级权限,则查询中的 可指定等级,表示查询该用户是否具有该等级的权限;也可以不指定等级,表示查询该用户具有该权限的等级。对于不分等级权限,只能查询该用户是否具有该权限,查询中不能指定等级。
输出格式
  输出共 q 行,每行为 false、true,或者一个数字。false 表示相应的用户不具有相应的权限,true 表示相应的用户具有相应的权限。对于分等级权限的不带等级查询,如果具有权限,则结果是一个数字,表示该用户具有该权限的(最高)等级。如果用户不存在,或者查询的权限没有定义,则应该返回 false。

样例

样例输入
3
crm:2
git:3
game
4
hr 1 crm:2
it 3 crm:1 git:1 game
dev 2 git:3 game
qa 1 git:2
3
alice 1 hr
bob 2 it qa
charlie 1 dev
9
alice game
alice crm:2
alice git:0
bob git
bob poweroff
charlie game
charlie crm
charlie git:3
malice game

样例输出
false
true
false
2
false
true
false
true
false

样例说明
  样例输入描述的场景中,各个用户实际的权限如下:
  * 用户 alice 具有 crm:2 权限
  * 用户 bob 具有 crm:1、git:2 和 game 权限
  * 用户 charlie 具有 git:3 和 game 权限
  * 用户 malice 未描述,因此不具有任何权限
  
评测用例规模与约定
  评测用例规模:
  * 1 ≤ p, r, u ≤ 100
  * 1 ≤ q ≤ 10 000
  * 每个用户具有的角色数不超过 10,每种角色具有的权限种类不超过 10
  约定:
  * 输入保证合法性,包括:
  1) 角色对应的权限列表(R 段)中的权限都是之前(P 段)出现过的,权限可以重复出现,如果带等级的权限重复出现,以等级最高的为准
  2) 用户对应的角色列表(U 段)中的角色都是之前(R 段)出现过的,如果多个角色都具有某一分等级权限,以等级最高的为准
  3) 查询(Q 段)中的用户名和权限类名不保证在之前(U 段和 P 段)出现过
  * 前 20% 的评测用例只有一种角色
  * 前 50% 的评测用例权限都是不分等级的,查询也都不带等级

笔记
权限计算
数据结构:map<string,map<string,int> 两个map :角色权限表,用户权限表

1用户:n角色;1角色:n权限 

1 读取并录入数据
	map<string,int> m; //角色,权限等级
	string 均为小写,
	新的权限加入:权限默认-1 表示不分等级,否则判断权限录入 int 
	若权限名相同:判断并更新等级 
	 
2 检索并输出结果 
	不分等级   true/false 
	分等级带等级  true/false
	分等级不带等级  (int)等级/否 


使用count,返回的是被查找元素的个数。如果有,返回1;否则,返回0。注意,map中不存在相同元素,所以返回值只能是1或0。
使用find,返回的是被查找元素的位置,没有则返回map.end()。	
代码
#include<iostream>
#include<vector>
#include<algorithm>
#include<map>
#include<string>
using namespace std;

map<string,map<string,int> > map_role_pri;//角色权限表
map<string,map<string,int> > map_user_pri;//用户权限表
 
int p,r,u,q; //权限数,角色数,用户数,检索查询数

void getPri(string &s,string &cata,int &level){
	cata=" ";
	level=-1;
	int i;
	for(i=0;i<s.size() && s[i]!=':';i++) cata+=s[i];
	if(s[i]==':') level=s[i+1]-'0';
}
int main(){
	string s,user,role,cata;
	int level,n;
	map<string,int> m;  
	
	//录入 p 段 ,不做处理 
	cin>>p;
	for(int i=0;i<p;i++) cin>>s;
		
	//录入 r 段
	cin>>r;
	for(int i=0;i<r;i++){
		cin>>role>>n;
		while(n--){
			cin>>s;
			getPri(s,cata,level);
//			cout<<s<<" "<<cata<< " "<<level<<endl;
			if(level==-1) m[cata]=-1;
			else m[cata]=m[cata]>level?m[cata]:level;
		}
		map_role_pri[role]=m;
		m.clear();
	}
	
	//录入 u 段
	cin>>u;
	for(int i=0;i<u;i++){
		map<string,int>::iterator it;
		cin>>user>>n;
		while(n--){
			cin>>role;
			for(it=map_role_pri[role].begin();it!=map_role_pri[role].end();it++){
				if(it->second==-1) m[it->first]=-1;
				else m[it->first]=m[it->first]>it->second?m[it->first]:it->second;
			}
		}
		map_user_pri[user]=m;
		m.clear();
	}
	
	//检索 q 段 
	cin>>q;
	for(int i=0;i<q;i++){
		cin>>user>>s;
		getPri(s,cata,level);
		//1 false:不存在用户,存在用户但无此权限,有此权限但级别不够高 
		if(map_user_pri.count(user)==0||map_user_pri[user].count(cata)==0
			||map_user_pri[user][cata]<level) cout<<"false"<<endl;
			
		//2 true:level!=-1 存在用户权限且权限够大,存在用户权限不分等级
		else if(map_user_pri[user][cata]==-1 || (level!=-1 && map_user_pri[user][cata]>=level))
			cout<<"true"<<endl;
			
		//3 (int):level==-1, 存在用户 返回最大等级 
		else if(level==-1) cout<<map_user_pri[user][cata]<<endl;
	}
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值