题目地址 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); } }