Test #1 2014/12/6题解

本文解析了ACM竞赛中的四道题目,包括PowerStrings、ThatNiceEulerCircuit、24Game及BalloonComes!。针对PowerStrings,介绍了如何使用KMP算法优化暴力解法;ThatNiceEulerCircuit题则是一个简单的数学问题;24Game通过构造方法解决了问题;BalloonComes!题涉及二元前缀表达式的计算。

题目地址 http://acm.njupt.edu.cn/vjudge/contest/view.action?cid=159#overview



A - Power Strings

其实这道题应该是四道题里最难的一题,但是被黄文锐用暴力给卡了过去。

暴力代码:

#include <stdio.h>
#include <string.h>
#define len strlen(s)
char s[1000000];
int main()
{
	int i, j, flag = 0;
	while (scanf("%s", s) != 1 || s[0] != '.')
	{
		for (i = len; i > 0; i--)
		{
			flag = 1;
			if (!(len%i))
			{
				for (j = 1; j < i; j++)
				{
					if (strncmp(s, s + len / i * j, len / i))
					{
						flag = 0;
						break;
					}
				}
				if (!flag)
					continue;
				else
				{
					printf("%d\n", i);
					break;
				}
			}

		}
	}
	return 0;
}


虽然这题因为数据不够强的问题让暴力卡了过去,但不是所有这类题目都会数据这么水。

这道题的标算是字符串匹配算法KMP。

附一个我觉得比较好的经典KMP算法的教学贴

http://www.matrix67.com/blog/archives/115


接下来,默认已经会了KMP算法,就可以利用KMP算法中next数组(又叫fail数组,即教学贴中的P数组)的性质

next[i]记录在匹配到B[i],但是B[i+1]匹配失败之后回到的位置。

换句话讲,对于每个next[i],字符串第0位到next[i]位与串第i-next[i]位到i位是一样的。

这样我们可以利用这个性质求出完全相同的前缀和后缀的最长长度。

接下来只要判len/(len-next[len])是否为整数即可,如果为整数的话就是len/(len-next[len])的值,否则n就为1。

标算代码:

#include<iostream>
#include <cstdio>
#include <cstring>
#define MAXN 1000005
using namespace std;

int next[MAXN],len;
char s[MAXN];
int main()
{
    while(scanf("%s",s)!=EOF)
    {
        if (strcmp(s,".")==0)	return 0;
	    int i=0,j=-1;  
	    len=strlen(s);
	    next[0]=-1;  
	    while(i<len)  //换了一种比较简明的求next数组的写法,本质是一样的。
	    {  
	        if(j==-1||s[i]==s[j])  
	        {  
	            i++;j++;  
	            next[i]=j;  
	        }  
	        else  
	            j=next[j];  
	    }  
	    if (len%(len-next[len])==0)
	    	printf("%d\n",len/(len-next[len]));
	    else
	    	printf("1\n");
    }
    return 0;
}

如果理解了kmp的话,很容易看出这个的时间复杂度是O(n)级别,而暴力是O(n^2)级别的,刚好数据比较水。。。



B - That Nice Euler Circuit

这个就是个阅读理解题,看懂了题目自然就会写了。根据题目弄出公式然后输入数据算即可。

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>

using namespace std;

double d,r,t;
double C;
int main()
{
	int cur=0;
	while (1)
	{
		cur++;
		scanf("%lf%lf%lf",&d,&r,&t);
		if (r==0)	return 0;
		C=d/5280/12*3.1415927*r;  //计算距离
		printf("Trip #%d: %.2f ",cur,C);
		C=C*3600/t; //计算MPH
		printf("%.2f\n",C);
	}
}


C - 24 Game

这个24点看似很难,其实稍微想一下。

4可以由1*2*3*4算出24,5的话可以由(5+4+3)*2*1算出24。(这只是其中一种构造方法,还有别的方法可以自己思考下。)

接下来所有的大于4的偶数都可以通过n-(n-1)=1得到1,然后不断对24*1即可。

大于5的奇数同理可以不断如此的24*1即可。


代码:

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

int n;

int main()
{
	scanf("%d",&n);
	if (n<4)	printf("NO\n");
	else
	{
		printf("YES\n");
		if (n%2==0)
		{
			for (int i=n;i>=5;i-=2)
					printf("%d - %d = 1\n",i,i-1);
					printf("4 * 3 = 12\n2 * 1 = 2\n12 * 2 = 24\n");
			for (int i=1;i<=(n-4)/2;i++)
				printf("24 * 1 = 24\n");
		}
		else
		{
			for (int i=n;i>5;i-=2)
				printf("%d - %d = 1\n",i,i-1);
				printf("5 + 4 = 9\n9 + 3 = 12\n12 * 2 = 24\n");
			for (int i=1;i<=(n-5)/2+1;i++)
				printf("24 * 1 = 24\n");			
		}
	}
}


D - Balloon Comes!

一个二元的前缀表达式计算,直接读取符号之后计算就行了,唯一要注意的细节就是在除号的时候能否整除要分开处理。

代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#define GC getchar()
using namespace std;

int a,b;

int main()
{
    int T;
    scanf("%d",&T);
    GC;
    while (T--)
    {
        char c=GC;
        scanf("%d%d",&a,&b);
        GC;
        if (c=='+')    printf("%d\n",a+b);
        if (c=='-')    printf("%d\n",a-b);
        if (c=='*')    printf("%d\n",a*b);
        if (c=='/')
            if (a%b==0)    
                printf("%d\n",a/b);
            else
                printf("%.2f\n",(double)a/b);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值