C实践习题集4

特殊的翻译

题目

小明的工作是对一串英语字符进行特殊的翻译:当出现连续且相同的小写字母时,须替换成该字母的大写形式,在大写字母的后面紧跟该小写字母此次连续出现的个数;与此同时,把连续的小写字母串的左侧和右侧的字符串交换位置;重复该操作,直至没有出现连续相同的小写字母为止。现在小明想请你帮他完成这种特殊的翻译。

输入格式:

输入一串由小写字母构成的字符串。(字符串长度不大于250)

输出格式:

输出翻译后的字符串。

输入样例1:

dilhhhhope

输出样例1:

opeH4dil

输入样例2:

lodnkmgggggggoplerre

输出样例2:

eG7lodnkmR2ople

思路

此题需要注意的其实就是小写字母连续重复的次数需要考虑大于9的情况(之前没考虑这个,在这里卡了很久呜呜呜),还有就是对字符串的操作(对检测到的满足条件的序列的起点和终点的标记)。

完整代码

#include<stdio.h>
#include<string.h>
void f(int first,int end);
char str[300],temp[300];
int flag;
int main()
{
	int i,j,first,end;
	scanf("%s",str);
	i=0;
	while(str[i]!='\0'){
		flag=0;
		if('a'<=str[i]&&str[i]<='z'&&str[i]==str[i+1]){
			first=i;
			j=i;
			do{
				j++;
			}while(str[j]==str[j+1]);
			end=j;
			f(first,end);
		}
		else i++;
		if(flag==1) i=0;
	}
	printf("%s",str);
	return 0;
}
void f(int first,int end)
{
	int i,j,gap;
	for(i=end+1,j=0;str[i]!='\0';i++){//把后一段字符串储存到另一个数组的前部
		temp[j++]=str[i];
	}
	temp[j++]=str[first]-32;
	gap=end-first+1;
	while(gap/10!=0){
		temp[j++]=gap/10+'0';
		gap=gap%10;
	}
	temp[j++]=gap+'0';
	for(i=0;i<first;i++){//把前一段字符串储存到另一个数组的后部
		temp[j++]=str[i];
	}
	temp[j]='\0';
	strcpy(str,temp);
	flag=1;
}

好吃的巧克力

题目

超市正在特价售卖巧克力,正好被贪吃的Lucky_dog看见了。

巧克力从左到右排成一排,一共有N个,M种。

超市有一个很奇怪的规定,就是你在购买巧克力时必须提供两个数字a和b,代表你要购买第 a 个至第 b 个巧克力(包含 a 和 b)之间的所有巧克力。

假设所有巧克力的单价均为1元。Lucky_dog想吃所有种类的巧克力,但又想省钱。作为Lucky_dog的朋友,他请你来帮他决定如何选择购买巧克力时的 a 和 b。

输入格式:

第一行包含两个正整数 N 和 M(M<=N, N<=10^6 , M<=2000),分别代表巧克力的总数及种类数。

第二行包含 N 个整数,这些整数均在1 至 M 之间,代表对应的巧克力所属的种类。

输出格式:

输出仅一行,包含两个整数a和 b(a<=b) ,由一个空格隔开,表示花费最少且包含所有种类巧克力的购买区间。

数据保证有解,如果存在多个符合条件的购买区间,输出a最小的那个。

输入样例:

12 5
2 5 3 1 3 2 4 1 1 5 4 3

输出样例:

2 7

思路

大佬题解
完成这题需要知道如何搜寻最优解。题目要求的不仅是能吃到所有种类巧克力的方案,而且还需要最省钱。因为只需求最优解,因此可以选用擂台法来筛选出最优解。

可以先找到满足条件的第一种情况:

for(i=0;sum<M;i++){
     if(k[n[i]]==0){
	   sum++;
     }
     k[n[i]]++;
     s1++;
}

然后将代表巧克力方案的序列(起点和终点之间的方案序列)往后推,即去掉序列头元素,接着检查此时序列是否仍能满足包含所有种类巧克力,若不能满足,说明需要从末尾继续向后寻找,直至找到相应种类的巧克力补上,或者超出所有巧克力数(搜索到达尽头),此过程用循环来完成,每次循环完成一次擂台对比,看看是否需要更新最优解。

完整代码

#include<stdio.h>
int k[2005]={0},n[1000005];//k数组用来记录每一种巧克力当前的数量
int main()
{
	int i,M,N,sum=0,s1=0,s2,start,last,first,end,store,flag;
	scanf("%d %d",&N,&M);
	for(i=0;i<N;i++) scanf("%d",&n[i]);
	for(i=0;sum<M;i++){//第一种情况 
		if(k[n[i]]==0){
			sum++; 
		}
		k[n[i]]++;//计算各种巧克力的个数 
		s1++;//巧克力总数 
	}
	first=0;//标记此时最优解序列的起点 
	start=0;//标记当前序列的起点 
	last=i-1;//标记此时最优解序列的终点
	end=i;//当前序列末尾+1 
	s2=s1;//s1为最优解的巧克力数量,s2为当前序列的巧克力数量 
	while(end!=N){
		flag=1;//标记判断是否越界 
		s2=s2-1;//s2为前一次方案所花的钱数
		k[n[start]]--;//把前一种的首个巧克力去掉 
		if(k[n[start]]==0){//需要往后补充 
			sum--;
			for(i=end;sum<M&&i<N;i++){
				if(n[i]==n[start]){
					sum++;
				}
				k[n[i]]++;
				s2++;
			}
			if(sum!=M) flag=0;
			end=i;
		}
		if(flag==0) break;//越界,直接结束循环 
		start++;
		if(s2<s1){//保证s1为目前最优解的巧克力总数 
			s1=s2;
			first=start;
			last=end-1;
		}
	}
	printf("%d %d",first+1,last+1);
	return 0;
}

下次一定(续)

题目

你是一个bilibili的六级号,由于经常一键三连,所以一个硬币都没有,现在你又做了个梦,在梦中你制定了一个硬币增加规则:

第一天登陆后硬币总数1个,第二天登陆后硬币总数112个,第三天登陆硬币总数112123个......,以此类推,梦中不知日月,你瞬间拥有了11212312341234512345612345671234567812345678912345678910123456789101112345678910......无穷多个硬币。

常年维护B站秩序的百漂怪看不下去了,决定随机挑一个数x,作为这个无穷数的第x位,如果你能正确答对这第x位上的数是什么,就赠送给你与这个数等量的硬币。

百漂怪总共会挑t次。

你决定编程模拟一下,搏一搏,单车变摩托。

输入格式:

第一行包含一个正整数t(1≤t≤10),表示百漂怪挑了t次。 接下来t行,每行一个正整数x (1 ≤ x≤ 2^31-1),表示第i次,百漂怪挑的是第x位。

输出格式:

输出共t行,每行输出对应第x位上的数。

输入样例1:

2
3
8

输出样例1:

2
2

输入样例2:

6
222
66666
99999999
66656565
22222
2

输出样例2:

6
4
9
4
1
1

思路

这题有一个测试点不管我怎么改,总是超时(我太难了呜呜呜),有无大佬来救救蒟蒻啊。
对于本题,我第一个想法是直接用字符数组完整模拟构造那个大数,然后根据输入的位数逐一输出即可。
但后面发现还是不好操作。
然后我又想了一个算法。通过观察,我们不难发现那个数的构造规律,举例说明的话:1->1 12->1 12 123 ,不难看出,112123比112多了1,2,3,而3是由2+1得到的,可推得接下去应该是1 12 123 1234
4由3+1得到,需要特别注意的是,之后会出现10,10这个数字需要用两个元素来存储(分成1和0)。
这样分析下来,每次在延伸该数时,必须做两次添加字符操作,如1->112,先将1后添加一个2,组成12字符串,然后把12字符串添加到“1”的后面。
没必要这么做,我们可以把这个数分段看,如1 12 123 1234 12345 123456 1234567 12345678,这样我们可以看到,其实只需要完成第一种添加操作就好了,我们的字符数组只需储存完成第一种添加之后的字符串即可(如12,123,1234......),只不过我们需要及时把需要输出的字符输出。
这样,我们来分析一下第一种的添加操作应该如何实现:我用一个num数组来储存一个标准数,每次将标准数加一,即可得到需要添加的字符,然后将其与前一次的字符串连接起来就行了。
我专门写了一个函数来完成此功能

void add(int len1)
{
	int i,extra=1,sum;
	for(i=0;i<len1;i++){
		sum=num[i]-'0'+extra;
		if(sum>=10){
			num[i]=sum-10+'0';
			extra=1;
		}
		else{
			num[i]=sum+'0';
			extra=0;
		}
		if(extra==0){
			break;
		}
	}
	if(extra==1){
		num[len1++]=1+'0';
	}
	num[len1]='\0';
}

值得注意的是,这里加法的实现还有一个问题,即需要逆序储存数字,这样数字的长度才是可增加的
模拟竖式运算:

//array index   1 2 3 4 5 6 7 8 9
                5 4 3 2 1
            +   7 8 9 9
            -------------
                2 3 3 2 2
//jw            1 1 1 1

//array index是数组下标,jw代表进位

如此的话,形成的字符串也需要是逆序储存才行
针对字符串的添加操作,同时及时储存所需要的值

void cal(int N,int key)
{
	int len1=strlen(num);
	while(count<N){//计算生成的新字符串的终点位置是否达到甚至超过所要求的位置,保证不错过所需位置的数据
		add(len1);
		str=num+str;
		len1=strlen(num);
		tot+=len1;
		count+=tot;
	}
	res[key]=str[count-N];
}

还有一点,在主函数里:

for(i=0;i<t;i++){
		cin>>a[i];
		order[i]=i;
	}
	for(i=1;i<t;i++){
		for(j=0;j<t-i;j++){
			if(a[j]>a[j+1]){
				s=a[j];
				a[j]=a[j+1];
				a[j+1]=s;
				s=order[j];
				order[j]=order[j+1];
				order[j+1]=s;
			}
		}
	}

我把所要求的位数从小到大排,并且用order标记输出顺序(即输入顺序)
这部分的代码是保证在构造那个数的过程中,那些数位可以及时被储存在res数组中的适当位置。

完整代码

#include<iostream>
#include<string>
#include<cstring>
using namespace std;
void cal(int N,int key);
void add(int len);
string str="1";
char num[100000]={"1"};
char res[15];
int count=1,tot=1;
int main()
{
	int t,i,j,a[15],s,order[15];
	cin>>t;
	for(i=0;i<t;i++){
		cin>>a[i];
		order[i]=i;
	}
	for(i=1;i<t;i++){
		for(j=0;j<t-i;j++){
			if(a[j]>a[j+1]){
				s=a[j];
				a[j]=a[j+1];
				a[j+1]=s;
				s=order[j];
				order[j]=order[j+1];
				order[j+1]=s;
			}
		}
	}
	for(i=0;i<t;i++){
		cal(a[i],order[i]);
	}
	for(i=0;i<t;i++) cout<<res[i]<<endl;
	return 0;
}
void cal(int N,int key)
{
	int len1=strlen(num);
	while(count<N){
		add(len1);
		str=num+str;
		len1=strlen(num);
		tot+=len1;
		count+=tot;
	}
	res[key]=str[count-N];
}
void add(int len1)
{
	int i,extra=1,sum;
	for(i=0;i<len1;i++){
		sum=num[i]-'0'+extra;
		if(sum>=10){
			num[i]=sum-10+'0';
			extra=1;
		}
		else{
			num[i]=sum+'0';
			extra=0;
		}
		if(extra==0){
			break;
		}
	}
	if(extra==1){
		num[len1++]=1+'0';
	}
	num[len1]='\0';
}
posted @ 2020-03-21 11:31  枭魈  阅读(350)  评论(0编辑  收藏  举报