【考题题解5】坐标系的特殊方法 字符串处理 递归

1.采蘑菇的拖拉机

【问题描述】

    春天来了,朱昶成的农场里会长很多蘑菇,而观察奶牛开着拖拉机采蘑菇成了朱昶成喜爱做的一件事情。

    朱昶成的农场被分为了一个平面坐标系,最左下角的坐标为(1,1),最右上角的坐标为(10^5,10^5).

    朱昶成有一个探测蘑菇的雷达,当开启蘑菇雷达后,这个雷达每一秒会发现农场上的一个蘑菇,并且会告知这个蘑菇的坐标。

    朱昶成的奶牛只会沿着一个方向开拖拉机,并且不会拐弯,这里的方向指的是和坐标轴平行的四个方向和与坐标轴夹角45度的对角线(当然是两条对角线)。并且每天朱昶成只允许奶牛开一次拖拉机,也就是说,每次采蘑菇,拖拉机只能沿着一个方向去采集所经过的点的蘑菇。

    朱昶成允许他的奶牛从农场里的任意一个点,任意一个方向出发,并且他的拖拉机的速度奇快,从启动到完成任务话费的时间忽略不计。现在朱昶成想直到,如果要一次性的采集K个蘑菇,最早在什么时间完成任务。

【输入】

为了防止骗分,测试数据为两组,每一组数据格式如下:

第一行两个整数N和K。表示有N个蘑菇出现,朱昶成要采集K个蘑菇。

       接下来N行,第i行为两个整数Xi和Yi,表示第i秒发现的蘑菇的坐标为Xi和Yi。

       在某一个坐标陆续发现多个蘑菇的可能性也是有的。

【输出】

两行,每行一个整数T,表示最早第T秒就可以完成K个蘑菇的采集。如果无法满足要求,那么这行输出-1.

 

【输入输出样例1】

tractor.in

tractor.out

4 3

1 2

3 4

3 2

4 5

5 2

1 1

2 1

1 2

1 3

1 4

4

2

第四秒开始,可以采集第1,2,4个蘑菇。

【数据范围】

   50% 数据保证Xi,Yi在[1..300]之间

  100% 数据保证N在[2..10^6]之间, K在[2..N]之间。Xi和Yi在[1..10^5]之间。

题目述概:

也就是题目分两组数据,每次给你一个坐标,每次判断坐标的行,列和45°角,然后那个先到达规定值就输出那个

题目思路:

1.判断行:很简单,用一个数组存储即可

2.判断列:同上

3.判断45°角:需要补充一下知识点:每条45°角的行列之和或之差都相

                              图一

如图一:每条45°角,即红线的行列之和都相等


                         图二

如图二:换一个方向的每条45°红线的行列之差相等

但是因为会有负数,再加上100000就好了

代码

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

int main()
{
	int a[1100000]={},b[1100000]={},c[1100000]={},d[2100000]={};
	int n,k,x,y,t=0;
	cin>>n>>k;
	for (int i=1;i<=n;i++)
	{
		cin>>x>>y;
		a[x]++;//行
		b[y]++;//列
		c[x+y]++;//正45°
		d[x-y+100000]++;//反45°
		if (a[x]==k||b[y]==k||c[x+y]==k||d[x-y+100000]==k)
		{
		   t++;
		   if (t==1) cout<<i<<endl;
    	}
		
	}
	cin>>n>>k;t=0;
	memset(a,0,sizeof(a));
	memset(b,0,sizeof(b));
	memset(c,0,sizeof(c));
	memset(d,0,sizeof(d));
	for (int i=1;i<=n;i++)
	{
		cin>>x>>y;
		a[x]++;
		b[y]++;
		c[x+y]++;
		d[x-y+100000]++;
		if (a[x]==k||b[y]==k||c[x+y]==k||d[x-y+100000]==k)
		{
		   t++;
		   if (t==1) cout<<i;
    	}
	}
	return 0;
 

 

2.加密工作

【问题描述】

2027年,从清华毕业的久知找了一份为一些文件的某些部分加密的工作,加密的部分是一串小写英文字母,加密的规则是这样的:要是连续出现相同的字母,则把他们替换成这个字母的大写形式,后面紧跟相同字母的个数,并把它之前跟之后的两端字符串调换,例如出现bcmatchingaef,则字符串变成:efA6bc。然后重新扫描字符串,直到没有出现相同小写字母为止。

【输入】

原始字符串(长度不大于250)。

【输出】

新的字符串。

 

【输入输出样例1】

password.in

password.out

bcmatchingaef

efA6bc

 

【输入输出样例2】

password.in

password.out

cmmmcefffg

gM3cF3ce

 

样例2解释:cM3cefffg——cefffgM3c——ceF3gM3c——gM3cF3ce

思路:题目不难,主要是运用一个substr函数,并考虑二位数的情况

#include<bits/stdc++.h>
using namespace std;
int main()
{
	string s;
	int k=1,i,j,ans;
	cin>>s;
	while (k)
	{
		k=0;
		for (i=0;i<s.size();i++)
		if (s[i]==s[i+1])
		{
			ans=1;
			for (j=i+1;j<s.size();j++)
			if (s[j]==s[i]) ans++;
			else break;
			if (ans>=10) s=s.substr(j,s.size()-j)+char(s[i]-32)+char(ans/10+48)+char(ans%10+48)+s.substr(0,i);
			else s=s.substr(j,s.size()-j)+char(s[i]-32)+char(ans+48)+s.substr(0,i);
			k=1;
            break;
		}
	}
	cout<<s;
	return 0;
}

3.小顾的字符游戏

【问题描述】

小顾和同学们喜欢玩一种游戏叫 "Moo".

他们总是站在一排,然后依次说出相应的一个字符,如果出错的同学,就要受到惩罚。

下面就是这个游戏的一个序列:

m o o m o o o m oo m o o o o m o o m o o o m o o m o o o o o

 

这个游戏的序列最初状态是 S(0) "m o o",也就是初始状态只有3个字符;如果要查询的字符超过3个,就要产生下一个字符序列,产生序列的规则如下:

 

s(k)是 s(k-1) +  "m o ... o"(k+2)个'o'  +s(k-1)

 

下面是相应的序列

S(0) = "m o o"

S(1) = "m o o m o o om o o"

S(2) = "m o o m o o om o o m o o o o m o o m o o o m o o"

 

 

注意:如果游戏的序列长度不够,就按照以上规则继续往下产生就可以了,所以游戏用的序列是无穷大的。

那么现在问题就出来了:

游戏中第x个人需要说的字符是什么呢?当然只有可能是 'm'或'o'.

本题有m(m<=10)个提问,每个提问给一个整数x,你要回答第x个人需要说出的字符数。

【输入】

第一行一个整数m(m<=10)

接下来m行,每行一个整数x (1 <=x<= 10^9)

 

【输出】

m行,每行一个字符,第i个人需要说的字符。

 

【输入输出样例1】

moo.in

moo.out

2

1

11

m

m

【数据范围】

  如题目描述。保证会有部分小数据查询位置在200以内。


大致思路:不难发现,每一组数据分成三段,两段和s(i-1)相同,另一段式m加上很多个o组成,然后只要用一个数组存储每一组数据的中间的两个交接点,然后用递归的方式去查找:如果查找的数字为s(0)的范围内,则直接输出;如果超范围了,则继续递归,如果递归在第一个点和第二个点之内,直接输出也很方便;但是在第二个点的范围之外,则递归s(i-1),知道递归到s(0)。

#include <bits/stdc++.h>
using namespace std;
struct moo
{
	long long len,dian1,dian2;
} a[40]={};//用结构体存储点一个点,第二个点,和长度
void find(int x)
{
	if (x==1){cout<<'m'<<endl;return;}
	if (x==2||x==3){cout<<'o'<<endl;return;}//如果范围在s(0)
	for (int i=1;i<=30;i++)
	{
		if (x>a[i].len)continue;//如何超范围
		if (x==a[i].dian1){cout<<'m'<<endl;return;}
		if (x>a[i].dian1&&x<a[i].dian2){cout<<'o'<<endl;return;}//如果在点一个点之后和在第二个点之前
		if (x>=a[i].dian2){find(x-a[i].dian2+1);return;}//递归s(i-1)
	}
}
int  main()
{
	a[0].len=3;
	a[0].dian1=a[0].dian2=0;
	for (int i=1;i<=30;i++)
	{
		a[i].len=a[i-1].len*2+i+3;
		a[i].dian1=a[i-1].len+1;
		a[i].dian2=a[i-1].len+i+4;
	}
	int n;
	cin>>n;
	for (int i=1;i<=n;i++)
	{
		int k;
		cin>>k;
		find(k);
	}
	return 0;
}//主体部分就不说了,自己看吧

 

                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值