菜鸟程设 A题日志》第三周
用以悼念我的国庆。
第九题 唬人的格子
现在觉得很多题把题意吃透了题就做出一半了,此题尤为如此。http://acm.uva.es/p/v7/795.html
那个英雄厉害之处就再于那个筛密码格转4下,空格就正好把正方形填满。(这个白空格还有其他组合方式么?)于是照着每次旋转后从左上到右下按顺序填密码,可以得到一个不变的先后序列矩阵,即KK神的某给力跟帖。先把乱码置成前一步骤的矩阵,然后照着对应序列矩阵的号码顺序,在每个长度为36的密码串的数组下标置存入即可。
#include"stdio.h"
#include "string.h"
int main(){
int key[36] = { 28, 1,19, 2,29,3, 20,30,10,31, 4,11, 32,21,5,12,22,33, 13, 6,34,23,7,14, 35,24,15,36,16,8, 25,17,26, 9,27,18};
int i=0,j=0,times=0,n=0;
charinp[110]="",secret[6][7],result[110]="";
while(gets(inp)!=NULL){
times=strlen(inp)/36;
for(n=0;n<times;n++){
for(i=0;i<6;i++){
for(j=0;j<6;j++){
secret[i][j]=inp[n*36+i*6+j];
}
}
for(i=0;i<6;i++)
{
for(j=0;j<6;j++){
result[n*36+key[i*6+j]-1]=secret[i][j];
}
}
memset(secret,'\0',sizeof(secret));
}
memset(inp,'\0',sizeof(inp));
for(i=times*36-1;i>=0;i--){
if(result[i]!='#')
printf("%c",result[i]);
else
break;
}
printf("\n");
}
return 0;
}
第十题 神人神法领悟即可http://www.bianchengla.com/team/27/practise/problem?id=1577
在自己的智力面前,很多原则还是需要让一让。
比如这种题不看各路神牛的经验方法,不各种问各种学我是理解不了的。
最终用的是省时省力不省脑的琛神三维魔方数组法(借用晨曦的比喻)。
很多人都说的很明白了,只是到了最后我还是不懂每个小格子里存的是神马,在豪绅的点拨下终于明白是每个字出现的次数。而每个字编码的不变位(XX位)则是对应的数组下标。于是豁然开朗,劈WA斩A。
#include"stdio.h"
#include "string.h"
int main(){
unsigned char part,word[3]="";
intsave[17][64][64],i=0,j=0,k=0,flag=0,illegal=0;
memset(save,0,sizeof(save));
while((scanf("%c",&part))!=EOF){
if(part<=128){
continue;
}
else{
if(part>=192&&part<224){
word[0]=part;
part=getchar();
if(part>=128&&part<192){
word[1]=part;
save[0][word[0]-192][word[1]-128]++;
}
else{
illegal++;
}
}
elseif(part>=224&&part<240){
word[0]=part;
part=getchar();
if(part>=128&&part<192){
word[1]=part;
part=getchar();
if(part>=128&&part<192){
word[2]=part;
save[word[0]-223][word[1]-128][word[2]-128]++;
}
else
{illegal++;
}
}
else
{illegal++;
}
}
}
}
for (i=0;i<17;i++){
for(j=0;j<64;j++){
for(k=0;k<64;k++){
if(save[i][j][k]>=2){
if(i==0){
printf("%c%c%d\n",j+192,k+128,save[0][j][k]);
flag++;
}
else{
printf("%c%c%c%d\n",i+223,j+128,k+128,save[i][j][k]);
flag++;
}
}
}
}
}
if (flag==0)
{printf("No repeat!\n");
}
if(illegal!=0){
printf("Illegal charactercount:%d\n",illegal);
}
return 0;
}
第十一题 最牛的回文
据说,如果有无穷多的母牛和无穷多的大型键盘,它们就可以创造出世界上最伟大的回文。在寻找回文时,可以不计文中的标点、空白和大小写,只要关注26 个英文字母就可以了。但是要注意,在输出时要按照原样,也就是要保留原有的空白、标点和大小写。
你的任务,就是在不超过 20000 个字符的字符串中,寻找长度不超过 2000 的回文字符串(含空格和标点时)。
输入格式
一段文本,不超过 20000 个字符,可以有一行或多行,每行的长度不超过 80 个字符。
输出格式
输出的第一行为找到的最长的回文字符串的长度。后面的行应该包括该字符串,字符串两边多余的空格和标点都不需要输出,但字符串中的空格、标点和换行则需要按照原样输出。
如果文中有多个长度相同的回文字符串,只要输出第一个就可以了。
最艰难的一题,三个版本,4个工程,无数用例,几近崩溃。说到底还是方法用错了。
第一版本是可怜的递归,还是用两边往中间判断,超时与错误一票。
第二版是可悲的马拉车Manacher算法,刚看懂的时候觉得本题的众多标点符号已经完全破坏了算法所要求的对称性,结果思索之后觉得可以再设一个对应原串的辅助数组pr,只要将p中的数字对应赋给pr就可以应用了。结果就是这简单的思想,让我功败垂成,其间处理令我头晕脑胀,基本浪费了一天。如有用马拉车成功的可以留贴交流http://blog.csdn.net/ggggiqnypgjg/article/details/6645824马拉车算法。
第三版才是无奈地回归群众,从中间往两边暴力,无压力迅速解开心结。
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
int main()
{
char c,str[21000]="",str1[21000]="";
int length[20000],p[20000];
inti=1,j=1,k=0,midpos=0,len=0,p1=0,pm=0,p3=0,max=0,first=0,last=0;
memset(p,0,sizeof(p));
memset(length,0,sizeof(length));
while ((c=getchar())!=EOF){
str[i]=c;
if(tolower(c)>='a'&&tolower(c)<='z')
{
str1[j]=tolower(c);
p[j]=i;
j++;
}
i++;
}
for (pm=1;pm<j;pm++)
{
if(str1[pm-1]!=str1[pm]&&str1[pm-1]==str1[pm+1])
{
p1=pm-1;
p3=pm+1;
len=1;
while(str1[p1]==str1[p3]){
len+=2;
p1--;
p3++;
}
if(p[p3-1]-p[p1+1]+1<=2000)
{
length[pm]+=len;
}
}
else if(str1[pm-1]==str1[pm])
{
p1=pm-2;
p3=pm+1;
len=2;
while(str1[p1]==str1[p3]&&(str1[p1]>='a'&&str1[p1]<='z')){
len+=2;
p1--;
p3++;
}
if(p[p3-1]-p[p1+1]+1<=2000)
{
length[pm]+=len;
}
}
else{
length[pm]=1;
}
}
for (k=1;k<j;k++)
{
if(length[k]>max)
{
max=length[k];
midpos=k;
}
}
printf("%d\n",max);
if (max%2==0)
{
first=p[midpos-max/2];
last=p[midpos+max/2-1];
}
else
{
first=p[midpos-(max-1)/2];
last=p[midpos+(max-1)/2];
}
for (i=first;i<=last;i++)
{
printf("%c",str[i]);
}
printf("\n");
return 0;
}
第十二题 破朔迷离的关键词
直接说疑惑吧,UVA原题的叙述http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=3&problem=111&mosmsg=Submission+received+with+ID+9325157“the numbers of the selected titles in numericalorder, separated by commas and with no spaces.”此句与网教题目中“词与词之间以空格、换行或标点符号分隔。”相比少了标点符号分隔这句。但是接下来的用例中一些可以被称作标点符号的( ) - --- ’都感觉不算可以分隔的标点,于是不明真相的群众们诚惶诚恐狂刷UVA防rejudge,求真相。
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
char p[50][20][25],t[250][100][25];
int mark[250][100];
int main(){
char pot,psg;
intmidlen[50],result[100],pflag=0,tflag=0,variable[90],len=0,v1=0,v2=0,v3=0,vflag=0;
int i=0,j=0,k=0,x=0,y=0,z=0;
int m=0,n=0,a=0,b=0;
int count=0,countword=0,times=0,t1=0;
memset(p,'\0',sizeof(p));
memset(t,'\0',sizeof(t));
memset(midlen,0,sizeof(midlen));
while((pot=getchar())!='#'){
if (pot=='P'){
scanf(":%d",&midlen[i]);
while((psg=getchar())!=10){
if((psg>='a'&&psg<='z')||(psg>='A'&&psg<='Z')){
if(pflag==0){
pflag=1;
}
p[i][j][k]=psg;
k++;
}
elseif(psg==' '||psg==10){
if(pflag==1){
pflag=0;
j++;
k=0;
}
}
}
i++;j=0;k=0;pflag=0;
}
else if(pot=='T'){
while((psg=getchar())!='|'){
if((psg>='a'&&psg<='z')||(psg>='A'&&psg<='Z')){
if(tflag==0){
tflag=1;
}
t[x][y][z]=tolower(psg);
z++;
}
elseif(psg==' '||psg==10){
if(tflag==1){
tflag=0;
y++;
z=0;
}
}
}x++;y=0;z=0;tflag=0;
}
}
for (m=0;m<i;m++){
memset(mark,0,sizeof(mark));
memset(result,0,sizeof(result));
j=0;
while (p[m][j][0]!='\0'){
j++;
}
for(n=0;n<j;n++){
y=0;
for(a=0;a<x;a++){
while(t[a][y][0]!='\0'){
y++;
}
for(b=0;b<y;b++){
if(strcmp(p[m][n],t[a][b])==0){
mark[a][b]=n+1;
}
}
}