【滨小之旅】模拟赛1 题解

T1 陶陶摘苹果

题目描述

陶陶家的院子里有一棵苹果树,每到秋天树上就会结出 n个苹果。苹果成熟的时候,陶陶就会跑去摘苹果。陶陶有个 t厘米高的板凳,当她不能直接用手摘到苹果的时候,就会踩到板凳上再试试。
现在已知 n个苹果到地面的高度,以及陶陶把手伸直的时候能够达到的最大高度h,请帮陶陶算一下她能够摘到的苹果的数目。假设她碰到苹果,苹果就会掉下来。

输入格式

输入包括三行数据
第一行为n,h和t分别表示院子中苹果的数量,陶陶伸手能达到的高度和板凳的高度
第二行包含 n 个 100到 200 之间(包括 100 和 200 )的整数分别表示 n 个苹果到地面的高度,两个相邻的整数之间用一个空格隔开。

输出格式

输出包括一行,这一行只包含一个整数,表示陶陶能够摘到的苹果的数目。

样例输入 #1

10 110 30
100 200 150 140 129 134 167 198 200 111

样例输出 #1

5

题目分析:

直接令陶陶的身高为H+T
判断有几个苹果小于H+T即可

#include
using namespace std;

const int N = 1e5+10;

int n,h,t;
int a[N];
int Ans = 0;

int main(){
	scanf("%d %d %d",&n,&h,&t);
	for (int i = 1; i <= n; i++) scanf("%d",&a[i]);
	int H = h+t;
	for (int i = 1; i <= n; i++) Ans+=(H>=a[i]);
	printf("%d",Ans);
	return 0;
}

T2 计数问题

题目描述

现在有q个询问
每个询问给出一个n和x,试计算在区间 1 到 n的所有整数中,数字 x(0<=x<=9)共出现了多少次?例如,在 1 到 11中,即在 1,2,3,4,5,6,7,8,9,10,11 中,数字 1 出现了 4 次。
请你给出这q个询问中每个询问的答案

输入格式

第一行一个整数q,表示一共有q个询问
第2~q+1行,每行2个整数n和x

输出格式

q行,每行一个整数,对应相应询问的答案

样例输入 #1

2
11 1
12 2

样例输出 #1

4
2

提示

对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 1 0 6 1\le n\le 10^6 1n106 0 ≤ x ≤ 9 0\le x \le 9 0x9


题目分析:

同样是一题很简单的模拟
直接循环一遍再累加即可
注意回答每个询问一下要重置变量

#include
using namespace std;

int q;
int n,x;
int Ans = 0;

int Plus(int xx,int m){
	int anss = 0;
	while (xx) anss+=((xx%10)==m),xx/=10;
	return anss;
}

int main(){
	scanf("%d",&q);
	while (q--){
		Ans = 0;
		scanf("%d %d",&n,&x);
		for (int i = 1; i <= n; i++) Ans+=Plus(i,x);
		printf("%d\n",Ans);
	}
	return 0;
}

T3 回文数

题目描述

若一个数(首位不为零)从左向右读与从右向左读都一样,我们就将其称之为回文数。

例如:给定一个十进制数 56 56 56,将 56 56 56 65 65 65(即把 56 56 56 从右向左读),得到 121 121 121 是一个回文数。

又如:对于十进制数 87 87 87

STEP1: 87 + 78 = 165 87+78=165 87+78=165
STEP2: 165 + 561 = 726 165+561=726 165+561=726
STEP3: 726 + 627 = 1353 726+627=1353 726+627=1353
STEP4: 1353 + 3531 = 4884 1353+3531=4884 1353+3531=4884

在这里的一步是指进行了一次 N N N 进制的加法,上例最少用了 4 4 4 步得到回文数 4884 4884 4884

写一个程序,给定一个 N N N 2 ≤ N ≤ 10 2 \le N \le 10 2N10 N = 16 N=16 N=16)进制数 M M M 100 100 100 位之内),求最少经过几步可以得到回文数。如果在 30 30 30 步以内(包含 30 30 30 步)不可能得到回文数,则输出 impossible

输入格式

两行,分别是 N N N M M M

输出格式

如果能在 30 30 30 步以内得到回文数,输出格式形如 STEP=ans,其中 ans \text{ans} ans 为最少得到回文数的步数。

否则输出 impossible

样例 #1

样例输入 #1

10
87

样例输出 #1

STEP=4

题目分析:

同样是模拟
我们注意到题目一直在重复一个过程:
取倒然后跟原数相加
直到当前数是个回文数

由于这个过程不断重复
所以我们可以设置一个函数去重复这个相加的过程

注意一下终止有两个条件:
1、STEP>30
2、当前数变成了回文数

#include
using namespace std;

const int N = 1e5+10;
string s;
int a[N],b[N]; 
int n,m;
int Ans = 0;

bool Check(){
	int l = 1,r = 50000;
	while (a[r] == 0) r--;
	while (l <= r){
		if (a[l] != a[r]) return 0;
		l++ , r--;
	}
	return 1;
}

void Go(){
	int r = 50000;
	while (a[r] == 0) r--;
	for (int i = r; i; i--) b[r-i+1] = a[i];
	for (int i = 1; i <= r; i++) a[i] = a[i]+b[i];
	for (int i = 1; i <= r; i++) a[i+1]+=a[i]/m,a[i]%=m;
}
int main(){
	scanf("%d",&m);
	cin>>s; n = s.length();
	for (int i = 0; i < n; i++) a[i+1] = s[i]-48;
	while (!Check() && Ans<=30) Go(),Ans++;
	if (Ans>30) printf("impossible");
	else printf("STEP=%d",Ans);
}

T4 删数问题

题目描述

键盘输入一个高精度的正整数 N N N(不超过 250 250 250 位),去掉其中任意 k k k 个数字后剩下的数字按原左右次序将组成一个新的非负整数。编程对给定的 N N N k k k,寻找一种方案使得剩下的数字组成的新数最小。

输入格式

输入两行正整数。

第一行输入一个高精度的正整数 n n n

第二行输入一个正整数 k k k,表示需要删除的数字个数。

输出格式

输出一个整数,最后剩下的最小数。

样例 #1

样例输入 #1

175438 
4

样例输出 #1

13

题目分析:

题目需要我们删除 k k k个数字之后使得最后的数字尽可能小

这个时候我们就要思考,什么时候一个数是尽可能小的?

  • 第一,当前数的长度尽可能小

但是,这道题要求我们删除k个数,所以最后的长度应该是一样的

在此条件下,我们继续思考,在长度一样的情况下,怎么样才能让一个数尽可能小呢?

  • 高位尽可能小

也就是说,我们通过删数,要使得这个数的高位变得尽可能小

删除什么样的数,能让这个数的高位变小呢?

例如有这个数1324

假设我们只能删一次数,我们会删那个数,让这个数的高位尽可能小呢?

首先,由于我们在意的是高位,所以我们会尽可能的从前往后删

于是我们开始尝试:

  • 删除1可行吗?
    显然不行,删除1之后,首位变成了3,整个数的高位变大了

  • 那删除3呢?
    好像是可行的,删除3之后,高位1没变,但是后面的一位由3变成了2,确实变小了

  • 删除2呢?
    不行,删除2之后,原本2的位置就会由4来顶替,是变大了

  • 删除4?
    可行,但是没有删除3的受益来的大

经过刚才的尝试,我们似乎找到了一点规律:
假设我们删除第 i i i个位置的数,那么第 i i i个位置的数就会由第 i + 1 i+1 i+1个位置的数去顶替。
那么什么时候删除第 i i i个位置的数,整个数会尽可能变小呢?
那就是第 i i i个位置的数比第 i + 1 i+1 i+1个位置的数要大的时候
这样删除了第 i i i个位置的数的时候就会让更小的第 i + 1 i+1 i+1个位置的数去顶替
这样总的数就变小了

但是光这还不够
我们之前说我们想让高位尽可能小
所以我们会尽可能的先删除高位
我们从前往后寻找,找到第一个符合条件的数就删除
而后重新从前往后再寻找……
直到删除满 k k k个数或者找不到满足条件的数的数为止

从上述条件中可以看出,当我们找不到符合条件的数的时候,我们的删数过程就会停止

那是否有一种情况,我们已经找不到符合条件的数了,但是我们删除的数还没到达 k k k个呢?

当然是有可能的。

那么这个数满足什么条件,他会找不到符合条件的数呢?
显然是单调递增的时候
每一位依次递增,自然不会存在第i位的数比第i+1位的数要大

这个时候,我们只需要从后往前依次删除,直到删满k个数为止

这样总结束了吧……

呵呵,还没有
一些特殊情况你考虑了吗?

比如删完的时候,当前数是0打头的
比如数字50074897删除两次
最后会得到004897这样的数
但是这显然不是一个正常的数啊!
我们需要去掉前导0

于是我们加上了去前导0的操作,松了口气。

你以为这样就好了吗?
呵呵

如果删完数字是000呢?
去完前导0之后这个数不就变成了一个空屁了吗?

这种情况还要特殊判断,需要输出0

这个时候你恐惧了,颤抖的说:“***,肯定还有情况!”

嘿嘿嘿
当然~~~
没了!

至此,这道题终于结束
功德圆满啦!

#include
using namespace std;

string s;
int k;

void Work(int x){
	int le = s.length();
	string ss = "";
	for (int i = 0; i < x; i++) ss+=s[i];
	for (int i = x+1; i < le; i++) ss+=s[i];
	s = ss;
}

int main(){
	cin>>s;
	cin>>k;
	while (1){
		int n = s.length();
	    bool f = 1;
		for (int i = 0; i < n-1; i++)
	      if (s[i]>s[i+1]){f = 0 , Work(i) , k--; break;}
	    if (k == 0 || f) break;
	}
	int Le = s.length();
	int st = 0;
	while (s[st] == '0' && st<Le-1) st++;
	for (int i = st; i <= Le-1-k; i++) cout<<s[i];
	return 0;
}

T4 智力大冲浪

题目描述

小伟报名参加中央电视台的智力大冲浪节目。本次挑战赛吸引了众多参赛者,主持人为了表彰大家的勇气,先奖励每个参赛者 m m m 元。先不要太高兴,因为这些钱还不一定都是你的。接下来主持人宣布了比赛规则:

首先,比赛时间分为 n n n 个时段,它又给出了很多小游戏,每个小游戏都必须在规定期限 t i t_i ti 前完成。如果一个游戏没能在规定期限前完成,则要从奖励费 m m m 元中扣去一部分钱 w i w_i wi w i w_i wi 为自然数,不同的游戏扣去的钱是不一样的。当然,每个游戏本身都很简单,保证每个参赛者都能在一个时段内完成,而且都必须从整时段开始。主持人只是想考考每个参赛者如何安排组织自己做游戏的顺序。作为参赛者,小伟很想赢得冠军,当然更想赢取最多的钱!注意:比赛绝对不会让参赛者赔钱!

输入格式

第一行为 m m m,表示一开始奖励给每位参赛者的钱;

第二行为 n n n,表示有 n n n 个小游戏;

第三行有 n n n 个数,分别表示游戏 1 1 1 n n n 的规定完成期限;

第四行有 n n n 个数,分别表示游戏 1 1 1 n n n 不能在规定期限前完成的扣款数。

输出格式

输出仅一行,表示小伟能赢取最多的钱。

样例 #1

样例输入 #1

10000
7
4 2 4 3 1 4 6
70 60 50 40 30 20 10

样例输出 #1

9950

提示

对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 500 1 \le n \le 500 1n500 1 ≤ m ≤ 5 × 1 0 5 1 \le m \le 5 \times 10^5 1m5×105 1 ≤ t i ≤ n 1 \le t_i \le n 1tin 1 ≤ w i ≤ 1000 1 \le w_i \le 1000 1wi1000


真服啦


题目分析:

题目要我们求什么呢?
希望求出我们能取得的最多的钱

最多的钱是什么意思?
扣得钱最少嘛

怎么样扣得钱可以最少呢?
那就是尽量先把扣钱多的项目先做掉嘛


这就是这道题贪心的第一个思路:
优先把扣钱多的项目做掉

所以我们需要先把项目按照扣钱数从大到小进行排序
在前面的项目尽可能先做

那么对于一个项目,我们要怎么去做才能做到最优呢?
是在靠后的时间点去做,还是在靠前的时间点去做呢?

对,就是在靠后的时间点去做。
为什么呢?
我们在如果在靠后的时间点把这个项目做掉了,那么我们在前面的时间点就有可能去完成其他的项目

不然,如果我们在前面就把这个项目做掉,就可能导致其他截止时间小的项目无法完成
对吧?


这就是我们的第二个贪心思路:
对于一个游戏,我们要在尽可能靠后的时间点去完成,这样才会给其他项目留下更多的额可能

#include
using namespace std;

int m,n;
struct Node{
	int t,w;
}a[101001];
bool f[101000];

bool cmp(Node a,Node b){
	return a.w>b.w;
}

int main(){
	scanf("%d\n%d",&m,&n);
	for (int i = 1; i <= n; i++) scanf("%d",&a[i].t);
	for (int i = 1; i <= n; i++) scanf("%d",&a[i].w);
	sort(a+1,a+n+1,cmp);
	for (int i = 1; i <= n; i++){
		bool F = 0;
		int T = a[i].t;
		while (f[T] && T) T--;
		if (T == 0) m-=a[i].w;
		else f[T] = 1; 
	}
	printf("%d",m);
}

你可能感兴趣的:(题解,算法)