【CSP-J模拟赛十一】题解

A石头剪刀布

题目

内存限制: 256 MB
时间限制: 1000 ms

题目描述

小T和小K在同一个小组,平时两人非常友爱,可每当轮到他们小组值日时,两人经常会为了扫地擦黑板之类的小事争执。一旦争执起来,他们就通过古老的猜拳游戏石头、剪刀、布来决定胜负(游戏规则:石头打剪刀,布包石头,剪刀剪布。),胜的一方获得优先选择权,如小T胜了他总是选择擦黑板,因为他长得人高马大,擦起黑板来挥洒自如,相对而言扫地就费劲多了,由于扫帚很短,他要把腰弯得很低才能扫到地面。

令小T烦恼的是他总是输多胜少,原因是小K常常在最后时刻变换手势,明明开始时是石头,可到了小T面前又变成了剪刀。

小T想了很久也没能想出什么好办法,直到有一天小T去某蒙看了电影《非诚勿扰》,影片中介绍了科学家秦奋发明“分歧终端机”的事迹,小T看完后深受启发,一回家就立刻着手制作起自己的“分歧终端机”来。

小T的“分歧终端机”形状是一个全封闭的长方体盒子,盒子的上表面装有一个电子显示屏,用来显示结果,左右两侧各有一个键盘,键盘上有3个键,上面标有数字1、2、3,分别代表石头、剪刀、布,如果选手要出石头则按1号键,要出剪刀则按2号键,要出布则按3号键。猜拳开始两位选手随即根据自己的意愿去按相应的键,如果第一次两人按的键相同,则不分胜负,继续第二次按键,直到决出胜负为止。

他希望你来帮他完成这个任务,这个任务非常简单,你可不能让小T失望哦~。

输入格式

仅有一行包含两个用空格隔开的不超过3的自然数,表示小T和小K所按键上的数字,1表示石头,2表示剪刀,3表示布。游戏规则是石头胜剪刀,剪刀胜布,布胜石头。

输出格式

仅有一行输出本次猜拳的结果,如果小T胜则输出“win”,如果小T输则输出“lose”,如果两人不分胜负则输出“tie”。注意输出时都用小写字母,引号不要输出。

样例

输入 #1

1 2

输出 #1

win 

分析

令人费解的题干长度。
没什么好说的,纯模拟(本蒟蒻懒得推通解,直接暴力判断了)。

#include<bits/stdc++.h>
using namespace std;
using ll=long long;

int a,b;

int main()
{
	cin>>a>>b;
	if(a==b)cout<<"tie";
	else if(a==1){
		if((b==2))cout<<"win";
		else cout<<"lose";		
	}
	else if(a==2){
		if((b==3))cout<<"win";
		else cout<<"lose";		
	}
	else if(a==3){
		if((b==1))cout<<"win";
		else cout<<"lose";		
	}

	
	return 0;
}

B保家卫国

题目

内存限制: 256 MB
时间限制: 1000 ms

题目描述

最近,有一个比较火的电视剧《特战荣耀》,如果大家看完以后,是否有当兵的想法呢?
这天下午,你正在看《特战荣耀》,突然,楼下有人在喊,说是部队来家乡招兵了,正合你意,你高兴的跑过去一看,发现招兵是有条件的(身高必须在160cm+),并且给补贴(补贴的很高,是以个人身高为基础,进行补贴)。
(1) 如果是男性,那么:
如果身高在170cm以下(包含170cm),将享受国家85%的补贴。
如果身高在170cm以上,180cm以下(含180cm)将享受国家80%的补贴。
如果身高在180cm以上,可以享受国家75%的补贴,还将获得一个惊喜大礼包。
(2) 如果是女性,那么:
如果身高在170cm以下(包含170cm),将享受国家90%的补贴。
如果身高在170cm以上,可以享受国家90%的补贴,还将获得一个惊喜大礼包。
请你根据性别和身高,计算一下可以享受国家多少补贴,以及是否可以领取大礼包。

输入格式

第一行一个字符’Y’或’C’ ,'Y’表示男性,'C’表示是女性。
第二行一个正整数,int范围内, 表示身高。

输出格式

第一行表示是否可以领取大礼包,如果可以输出’YES’,否则输出’NO’。
第二行一个实数,保留两位小数,表示享受的补贴。

样例

输入

Y
189

输出

NO
144.00 

分析

同A题。

#include<bits/stdc++.h>
using namespace std;
using ll=long long;

char a;
int b;

int main()
{
	cin>>a>>b;
	//if(b<160){
	//	cout<<"NO\n0";
	//	return 0;
	//}并没有关于这个特判的测试点,可有可无
	if(a=='V'){
		if(b<=170)
			printf("NO\n%.2lf",b*0.85);
		else if(b<=180)
			printf("NO\n%.2lf",b*0.8);
		else printf("YES\n%.2lf",b*0.75);
	}
	else {
		if(b<=170)
			printf("NO\n%.2lf",b*0.9);
		else printf("YES\n%.2lf",b*0.9);		
	}
	
	return 0;
}

C 数字游戏

题目

内存限制: 256 MiB
时间限制: 1000 ms

题目描述

你的朋友在玩数字游戏,游戏规则如下:
起始数字为 x x x ,每一轮如果 x x x的最大质因子大于 p p p时, x x x增加1点。
请你计算出经过尽可能多轮游戏后,最终的 x x x值。

输入格式

两个整数 x x x, p p p

输出格式

一个整数,表示你最终的 x x x值。

样例

【样例1输入】

666 2

【样例1输出】

1024

【样例2输入】

114514 3

【样例2输出】
118098

【样例3输入】

1919810 9

【样例3输出】

1920000

【样例4输入】

314159265 2

【样例4输出】

536870912
数据范围与提示

对于10% 的数据,保证 p = 2 p = 2 p=2
对于30% 的数据,保证 x ≤ 20 x ≤ 20 x20
对于另外10% 的数据,保证 p = 2 p = 2 p=2
对于70% 的数据,保证 x ≤ 1 0 6 x ≤ 10^{6} x106
对于另外10% 的数据,保证 p = 2 p = 2 p=2
对于100% 的数据,满足 2 ≤ x ≤ 6 × 1 0 8 2 ≤ x ≤ 6×10^{8} 2x6×108 2 ≤ p ≤ 10 2 ≤ p ≤ 10 2p10


分析

本场比赛第一道非红题。话说csp-j模拟赛怎么越来越水了。

通过题意,我们发现最终的 x x x 值即为不小于初始 x x x 值得最小的最大质因子不大于 p p p 的数,即其质因数都为小于 p p p 的质数。

但是 x x x 的值太大,暴力枚举显然会 T L E TLE TLE。因为数据范围中的 1 ≤ p ≤ 10 1\le p\le 10 1p10 非常小,所以从此入手。 10 10 10 以内的质数只有 2 , 3 , 5 , 7 2,3,5,7 2,3,5,7,我们可以定义一个优先队列 q q q(小顶堆),初始队列为所有不大于 p p p 的素数。然后每次弹出队头,即目前最小的满足条件的数,判断其是否不小于 x x x,不小于则输出,否则枚举小于 p p p 的素数,然后将两数相乘后放入 q q q。根据素数唯一分解定理,生成的数不会重复。

关于时间复杂度…反正能过(我不会证)。

#include<bits/stdc++.h>
using namespace std;
using ll=long long;

int x,p;
priority_queue<ll,vector<int>,greater<int> >q;
int a[6]={0,2,3,5,7,11};//多写一个作为边界

int main()
{
	cin>>x>>p;
	ll ans;
	for(int i=1;a[i]<=p;i++)
		q.push(a[i]);
	while(1){
		int t=q.top();q.pop();
		if(t>=x){
			ans=t;
			break;
		}
		for(int i=1;a[i]<=p;i++)
			q.push(t*a[i]);
	}
	cout<<ans;
	
	return 0;
}

D 魔力碎片

题目

内存限制: 256 MiB
时间限制: 1000 ms

题目描述

你的手中共有 x x x点「魔力碎片」。
每次,你可以消耗 k k k点「魔力碎片」进行「融合」,得到1点「魔力」并返还 p p p点「魔力碎片」。
请你求出你可以获得的「魔力」的最大值。

输入格式

三个整数 x x x, k k k, p p p

输出格式

仅一个数,表示你可以获得的「魔力」的最大值。

样例

【样例1输入】

6 3 2

【样例1输出】

4

【样例2输入】

114514 666 233

【样例2输出】

263

【样例3输入】

1000000000000666 50000001919810 5000000114514

【样例3输出】

62088969
数据范围与提示

对于10% 的数据,保证 p = 0 p = 0 p=0
对于50% 的数据, 0 ≤ x , p ≤ 1 0 3 0 ≤ x,p ≤ 10^{3} 0x,p103 p ≤ k ≤ 1 0 3 p ≤ k ≤ 10^{3} pk103
对于另外20% 的数据,保证 x < k x < k x<k
对于100% 的数据, 0 ≤ x , p ≤ 1 0 18 0 ≤ x,p ≤ 10^{18} 0x,p1018 p ≤ k ≤ 1 0 18 p ≤ k ≤ 10^{18} pk1018
题目保证答案不大于 1 0 18 10^{18} 1018


分析

每次操作都会使 x x x 的值减去 k − p k-p kp,所以只要求出 ⌊ x k − p ⌋ ⌊\frac{x}{k-p}⌋ kpx 即可…

显然,这是错误的。当进行到某次操作使 k − p < x < k k-p<x<k kp<x<k 时,上面的式子会错误的多计算 ⌊ x k − p ⌋ ⌊\frac{x}{k-p}⌋ kpx 点(这里的 x x x 为某次操作后得值而非初始值)。

所以,我们可以将计算分为两部分。先计算出当剩余值大于 x − k x-k xk 时对答案的贡献,推得贡献为 ⌊ x − k k − p ⌋ ⌊\frac{x-k}{k-p}⌋ kpxk。然后, x x x 的值就只剩下 k k k 点,正好可以再进行一次操作,贡献为 1 1 1。两次操作剩余值之和显然不会达到 k k k

所以,我们可以得到答案为:
⌊ x − k k − p ⌋ + 1 ⌊\frac{x-k}{k-p}⌋+1 kpxk+1

此外,还有一个特判要注意。当 x < k x<k x<k 时,无法进行操作,直接输出 0 0 0

code(疯狂压行版)
#include<bits/stdc++.h>
using namespace std;
long long x,k,p;
int main()
{
	cin>>x>>k>>p;
	if(x<k)return !(cout<<0);
	return !(cout<<(x-k)/(k-p)+1);
}

E Present

题目

内存限制: 256 MiB
时间限制: 1000 ms

题目描述

很多人,都有着奋力挣扎的当下。
车水马龙,人来人往。有很多人渐渐进入你的生活,也有很多人陆续淡出你的视野。
为了方便,用整数来标识每个人。你的思绪可以类比成一根绳索,而每个人就像穿上去的珍珠。每一天,可能有一颗“珍珠”从最左侧或最右侧加入了这条绳索;也有可能会有一颗“珍珠”被你从最左侧或最右侧取下;甚至也有可能发生了些变故,致使你的整个“项链”左右翻转了过来。
每当一个人离开的时候,你总会缅怀一下他,输出标识他的数字来结束这一段关系。
最开始你的思绪中空无一人。在接下来的这 n n n天中,你又会先后缅怀哪些人呢?

输入格式

第一行一个整数 n n n, i d id id,表示需要处理的天数和测试点编号(方便您获取部分分,见“数据范围与提示”部分)。
接下来 n n n行,每行的格式是以下5种之一:

  • 0   x 0\ x 0 x:从最左侧加入标识为 x x x的人( x x x是一个整数)
  • 1 1 1:移除并缅怀最左侧的人(要求输出其标识)。若不存在,输出 0 0 0
  • 2   x 2\ x 2 x:从最右侧加入标识为 x x x的人( x x x是一个整数)
  • 3 3 3:移除并缅怀最右侧的人(要求输出其标识)。若不存在,输出 0 0 0
  • 4 4 4:使思绪颠倒(整条“项链”左右翻转)
输出格式

每当操作为 1 1 1 3 3 3时,输出一行一个整数,表示被移除的人的标识数(若不存在则输出 0 0 0)。

样例

【样例1输入】

8 0
1
2 111
0 222
4
0 333
3
1
3

【样例1输出】

0
222
333
111

第 1 天,试图移除最左侧的人,但此时思绪为空不存在最左侧的人,故输出 0。
第 2,3 天在右侧加入 111,左侧加入 222 后你的思绪可以表示为 “222 111”。
第 4 天翻转变为 “111 222”。
第 5 天左侧加入 333 得到 “333 111 222”。
第 6 天移除并输出最右侧的 222 剩下 “333 111”。
第 7,8 天同理。

数据范围与提示

数据范围


分析

直接用 S T L STL STL 的双端队列或手写双端队列模拟即可(我用的是 S T L STL STL)。需要注意的是,翻转队列使用一般写法可能会超时,记录一个变量 i o io io 判断当前方向即可。

#include<bits/stdc++.h>
using namespace std;
#define int long long

int n,id,io=1;
deque<int> q;

signed main()
{
	cin>>n>>id;
	while(n--){
		int op;cin>>op;
		if(op==0){
			int x;cin>>x;
			if(io==1)
				q.push_front(x);
			else q.push_back(x);
		}
		else if(op==1){
			if(q.empty())cout<<"0\n";
			else 
				if(io==1){
					cout<<q.front()<<"\n";
					q.pop_front();
				}
				else {
					cout<<q.back()<<"\n";
					q.pop_back();
				}
		}
		else if(op==2){
			int x;cin>>x;
			if(io==-1)
				q.push_front(x);
			else q.push_back(x);
		}
		else if(op==3){
			if(q.empty())cout<<"0\n";
			else 
				if(io==-1){
					cout<<q.front()<<"\n";
					q.pop_front();
				}
				else {
					cout<<q.back()<<"\n";
					q.pop_back();
				}
		}
		else if(op==4)
			io*=-1;
	}
	
	return 0;
}

F 人赢

题目

内存限制: 256 MiB
时间限制: 1000 ms

题目描述

在某个群里,有一个人赢,他很关心群友的未来前途。
在把群友从 1 到 n n n编号后,他给每个群友的人生做出了评价,用人生路值来表示,记作 c i c_i ci
群友的数量 n n n恰好是偶数,所以他想出了一个好办法:相对帮扶。
他发现,一对群友的人生路值差距越大,他们之间相互帮扶的效果就越好。具体而言,如果这对群友的人生路值分别是 c a c_a ca c b c_b cb,那么就会产生 ( c a − c b ) 2 (c_a - c_b)^2 (cacb)2的效果。
他想知道在合理结对之后,产生的效果之和最大是多少。如果有能力的话,他还想让你具体地给出能产生这么多效果的方案是如何结对的。(每个人必须参与且仅参与一次结对)

输入格式

第一行给出两个整数 n n n, f l a g flag flag,表示群友的人数,以及是否需要输出方案。
第二行 n n n个正整数 c i c_i ci,表示编号为 i i i的群友的人生路值。

输出格式

第一行一个整数,表示可能的最大的效果和。
此后如果 f l a g flag flag为 0,不需要输出其它内容。否则你还需要按如下格式输出方案:
n 2 \frac{n}{2} 2n行,每行两个整数 x x x, y y y表示要让编号为 x x x y y y的群友结成一对,其中要求 c x ≥ c y c_x \geq c_y cxcy
先输出产生的效果更大的一对,如果有两对产生的效果大小相同,则顺序任意。
若存在多种方案,输出任意一种即可。

样例

【样例1输入】

4 0
22 44 33 11

【样例1输出】

1210

【样例2输入】

4 1
22 44 33 11

【样例2输出】

1210
2 4
3 1

两个样例情况相同,第一个不要求输出方案,第二个要求输出方案。
可以证明 2 和 4 组队、1 和 3 组队能产生的总效果是最大的。由于 ( c 2 − c 4 ) 2 ≥ ( c 3 − c 1 ) 2 (c_2 - c_4)^2 \geq (c_3 - c_1)^2 (c2c4)2(c3c1)2,所以先输出 ( 2 , 4 ) (2,4) (2,4)这一对后输出 ( 1 , 3 ) (1,3) (1,3)这一对。由于 c 2 ≥ c 4 c_2 \geq c_4 c2c4 所以在输出这一对时先输出 2 后输出 4,由于 c 3 ≥ c 1 c_3 \geq c_1 c3c1所以在输出这一对时先输出 3 后输出 1。

数据范围与提示

数据范围


分析

初中数学题。

先排序(从小到大或从大到小皆可),然后从两边到中间依次选择结对对象,即对于第 i i i 个入,TA的帮扶对象为第 n − i + 1 n-i+1 ni+1 个入。然后再算出答案即可。

如何证明?考虑当 n = 4 n=4 n=4 时, c 1 ≤ c 2 ≤ c 3 ≤ c 4 c_1\le c_2\le c_3\le c_4 c1c2c3c4,考虑所有组合对答案的贡献,使用作差法易证 c 1 c_1 c1 c 4 c_4 c4 c 2 c_2 c2 c 3 c_3 c3 结对的贡献是最大的。同理,可推得 n n n 更大的情况。

然后就是如何输出方案。显然,组合 ( i , n − i + 1 ) (i,n-i+1) (i,ni+1) 的贡献要比 ( i + 1 , n − i − 1 + 1 ) (i+1,n-i-1+1) (i+1,ni1+1) 的贡献大,所以按从两边到中间的顺序输出即可。

还有一点特别重要,答案的值可能超过 long long 的范围,需要 unsigned long long(卡了我一个小时QWQ)。

具体细节见代码
#include<bits/stdc++.h>
using namespace std;
#define int unsigned long long
const int N=2e5+5;

int n,flag,ans;
struct pl{
	int c,id;
}a[N];

bool cmp(pl x,pl y){
	return x.c<y.c;
}

signed main()
{
	cin>>n>>flag;
	for(int i=1;i<=n;i++){
		cin>>a[i].c;
		a[i].id=i;
	}
	sort(a+1,a+1+n,cmp);
	int l=1,r=n;
	while(l<=r){
		ans=ans+(a[r].c-a[l].c)*(a[r].c-a[l].c);
		l++;
		r--;
	}
	cout<<ans<<"\n";
	if(flag){
		l=1,r=n;
		while(l<=r){
			cout<<a[r].id<<" "<<a[l].id<<"\n";
			l++,r--;
		}
	}
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值