Test #1 2014/12/6题解

来源:互联网 发布:微商团队怎么优化 编辑:程序博客网 时间:2024/04/27 17:05

题目地址 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 1000005using 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; //计算MPHprintf("%.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);    }}
0 0