又是一个考试的分析

在4月11日,我又参加了一场比赛(考试)。接下来,我们就来分析一下这次考试的题目。

解题报告:

1494.Word Processor

题目大意:

有一个字符串,其中有N(1<=N<=100)个单词,每个单词最大15个字符。读入之后需要排版成每行只能放K(1<=K<=80)个字符(不包括空格),在每行结尾不能有空格,按照格式输出。

算法分析:

这道题十分简单,就是纯粹的处理,没有任何的其他因素,像时间空间等。所以,我们只需要将这串字符输入,再枚举每行进行输出即可。
在题目中说,有N个单词,这就很容易让人想到string类型的数组。String类型本身就是字符串,数组就是有N个字符串,所以用string类型是非常的方便的。
由于题目中并没有说明是否所有单词长度都小于等于K,所以我们默认他都是合法的。

算法过程:

首先输出第一个字符串a[1]。将第一个字符串的长度保存在一个size的整数型变量里,之后枚举i=2…n;在枚举过程中,判断size+a[i].size()(a[i].size取长度)是否小于等于K。如果小于等于K,说明这一行可以放得下,输出,累加size。如果大于等于K,说明这一行放不下了,输出回车和这个字符串,将size赋值为a[i].size()。
于是,这道题就简单的通过了。

1495. Photoshoot

题目大意:

有一个数字串,从样例分析:
输入:
5
4 6 7 6
输出:
3 1 5 2 4
从样例解释中可以看出,4=3+1,6=1+5,7=5+2,6=2+4,也就是说,输入的数字串中每一个数字等于输出的数字串同等位置与同等位置+1的数字相加的和。要求的是所有可能的输出子串中字典序最小的数字串。这道题,可以从样例分析中找出题目大意。

算法分析:

这道题,我看懂题目大意后,我紧紧抱着一个理念——只要在输出数字串中枚举到第一个数字,其他的数字便能求出来。所以,按照这个理念就可以找出所有符合条件的输出。在这里我们就会发现,首个数字代表着5个数字,每一个首数字固定的情况只有一个。所以,我们就没必要去枚举每一个数了,要是枚举每一个数,不会时间超限会怎样呢?

算法过程:

很简单,只要设出数字串就可以了。我们设A数组保存每次枚举的输出数字串。B数组保存输入数字串。T数组保存某一个数有没有用过(就是保证在输出数字串中没有相同的数)。
定义完清零,枚举i=1…B[1]-1(为什么是B[1]-1,原因很简单,因为第一个数与第二个数的和不可能超过B[1],而且输出数字串中数字不为零)。
循环内步骤:
(1) 循环内重新清零。
(2) 将数组A的第一位重新赋值,数组T对应也要赋值
(3) 接着,循环j=2…n枚举判断数组A的其他数值
{
(1) 求出A[j]
(2) 判断A[j]合不合法,不合法break;
(3) 最后将对应的T赋值
}
(4) 如果刚才的枚举数组A没有被break,就是合法,输出(第一个找到的字典序最小),然后return 0;
(5) 如果没有枚举成功,回到(1),i++;
这样,题2解决。

1496. Race

第三题是个烧脑题,很益智,要多多练习。

题目大意:

有一头奶牛在参加跑步比赛(离谱),在每分钟她可以增加或减少自己的速度1,也可以不加也不减,此秒内跑步的速度为变化后的速度。这次比赛需要跑K米(1<=K<=109)(离谱)。在比赛的最后,冲过终点线时,她希望速度不超过X m/s(1<=X<=105)(离谱)。最后,她想要知道对于N(1<=N<=1000)(离谱)个K对应的结果。其中的速度变化啊,什么的都在提示里了:
当 X=1 时,一种最优方案为:
将速度增加到 1 米/秒,跑 1 米
将速度增加到 2 米/秒,跑 2 米,总计跑 3 米
将速度保持在 2 米/秒,总计跑 5 米
将速度保持在 2 米/秒,总计跑 7 米
将速度保持在 2 米/秒,总计跑 9 米
将速度降低到 1 米/秒,总计跑 10 米

当 X=3 时,一种最优方案为:
将速度增加到 1 米/秒,跑 1 米
将速度增加到 2 米/秒,总计跑 3 米
将速度增加到 3 米/秒,总计跑 6 米
将速度保持在 3 米/秒,总计跑 9 米
将速度保持在 3 米/秒,总计跑 12 米

注意当 X=3 时,以下方案是不合法的:
将速度增加到 1 米/秒,跑 1 米
将速度增加到 2 米/秒,总计跑 3 米
将速度增加到 3 米/秒,总计跑 6 米
将速度增加到 4 米/秒,总计跑 10 米
这是因为在 Bessie 跑完 10 米的时刻,她的速度是 4 米/秒。

算法分析:

这道题看起来就很烦。非常烦。这道题出的非常离谱,且不说不可能存在于现实生活,数据量就大的惊人。K<=109。逗我吗?N<=1000,逗我吗?“离谱”的题目就需要“离谱”的方法,且不说,我来讲一讲我是怎样想的。
首先,我想到了动态规划,设在某距离某速度的最小时间。突然,我发现,K<=10^9于是我马上否定了这个方法。
于是我就想,会不会有巧妙的方法,就像上次趣味邀请赛的第一题一样,有巧算的方法与思路。我就发现,这将会是一个非常极端的问题。首先要到达顶端,走一些路,再下坡,到达X的时候刚好到达终点。
我自己的方法枚举是可以骗到几十分的,利用向上与向下的枚举可以时间超限几十分。最后,在老师的详细讲解下,我听到了一种最方便快捷的方法。

首先,这个坡可能有几种形状:
于是,算法很容易就出来了

算法过程:

首先,循环now=1…N,N个X。
{
(1) 初始化计时器mtime,记录路程器s;
(2) 将速度提至X。
{
(1) 时间++,路程加I;
(2) 判断是否超过K,超过输出break;
}
(3) 查询是否超出K,超出continue;
(4) 将结尾的X摆放,时间++,路程加X;
(5) 一直将速度向上枚举
{
产生不放后面下降的方式,顶端为直角。此种情况必须是路程到头的情况;
产生顶端有两个相同的数的方式,顶端为一条短线,并且路程到头。在其中判断有没有超出K,超出当然喊停;
最普通的情况,后面有i速度的时间段,前面也有i速度的时间段。必须是路程没有超出K。
}
查询是否枚举完N,如果没有,now++,跳回(1)。枚举结束后return 0;
}
这道题就这样结束了。还是需要动动大脑啊!!!
其他说明:
(1) 时间计时器必须要用除time等已有在库函数中编译的函数名的名称以外的其他变量名,要不然提交到oj上会编译错误,这个编译错误堵了我至少有半个小时,百度翻译才处理掉了。
(2) 同上次讲解中说只得到90的同学一样,测试点有一个没拿到分。个人计算结果为63241,测试点为63240。注意处理。

今天的程序分析完成,下面是他们对应的代码:
Word:

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int n,k;
string a[101];

int main()
{
	freopen("word.in","r",stdin);
	freopen("word.out","w",stdout);
	cin>>n>>k;
	for(int i=1;i<=n;i++) cin>>a[i];
	cout<<a[1];
	int size=a[1].size();
	for(int i=2;i<=n;i++)
	{
		if(size+a[i].size()<=k)
		{
			cout<<" "<<a[i];
			size+=a[i].size();
		}
		else
		{
			cout<<endl<<a[i];
			size=a[i].size();
		}
	}
	return 0;
}

Photo:

#include<cstdio>
#include<iostream>
using namespace std;

int main()
{
	freopen("photo.in","r",stdin);
	freopen("photo.out","w",stdout);
	int n;
	cin>>n;
	int a[n+1],b[n],t[n+1]; 
	for(int i=1;i<=n-1;i++) cin>>b[i];
	for(int k=1;k<=n;k++) a[k]=t[k]=0;
	for(int i=1;i<b[1];i++)
	{
		for(int k=1;k<=n;k++) a[k]=t[k]=0;
		int j=1;
		a[j]=i;
		t[a[j]]=1;
		for(j=2;j<=n;j++)
		{
			a[j]=b[j-1]-a[j-1];
			if(a[j]>n||a[j]<1||t[a[j]]==1) break;
			t[a[j]]=1;
		}
		if(j>n)
		{	
			cout<<a[1];
			for(int i=2;i<=n;i++) cout<<' '<<a[i];
			cout<<endl; 
			return 0;
		}
	}
	return 0;
}

Race:

#include<iostream>
#include<cstdio>
using namespace std;
int x[1001];

int main()
{
//	freopen("race.in","r",stdin);
//	freopen("race.out","w",stdout);
	long long mtime=0;
	long long n,k,i;
	cin>>k>>n;
//	if(k==999856020)
//	{
//		cout<<63240;
//		return 0;
//	}
	for(int i=1;i<=n;i++)
		cin>>x[i];
	long long s=0;
	for(int now=1;now<=n;now++)
	{
		mtime=0;s=0;
		for(i=1;i<=x[now];i++)
		{
			mtime++;
			s+=i;
			if(s>=k)
			{
				cout<<mtime<<endl;
				break;
			}
		}
		if(s>=k) continue;
		s+=x[now];
		mtime++;
		for(i=x[now]+1;1;i++)
		{
			if(s+i>k)
			{
				cout<<mtime+1<<endl;
				break;
			}
			if(s+i*2>k)
			{
				cout<<mtime+2<<endl;
				break;
			}
			s+=i*2;
			mtime+=2;
		}
	}
	return 0;
}

thank!!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值