一行盒子
题意理解:
给一行数字(给出个数,从小到大从做到右排列),经过一些变化后,输出其顺序排在奇数位置上的数的和。
一个n,表示n个数顺序排列(1-n);
一个m,表示每次变化;
接着m次变化操作:
1 、u x y,把x移动到y的左边(u=1);
2 、u x y,把x移动到y的右边(u=2);
3 、u x y,把x和y的位置调换(u=3);
4 、u,把序列翻转过来,方向调转;
思路解析:
这个题目,在省赛回来后A出来,把代码贴上来,一直心痛,就没有再碰过。今天来写完它,真的是一道伤口,害怕揭开后的疼痛,是整个心都痉挛。
最开始的时候,对map和set不够熟悉,看到里面的insert(iterator,x),以为可以把键插到中间,直接就做了。这和比赛前一直用STL有关系,非常依赖STL。后面真的按照这个思想敲了,等我花了将近半小时敲完的时候才发现,即使是insert还是改变不了map里面的重头到尾的插入顺序,整个思想是对的,但是,map的插入方式却直接击溃了整个精神,当时离比赛结束只有20分钟,直接与AC无缘。这构成了我ACM人生的一大遗憾。最终,由于本题没能A出来,与奖杯距离六步之遥。。。再也不要“深藏功与名”!!
谨以此告诫所有主攻STL的同僚,要不就别学,要学就一定要搞清楚所以然,不要重蹈我的覆辙。
ACM毁大学,AC毁一生!
后来听说用双向链表可以过,自己写了个裸链表。。。答案是没问题,一提交就看到了TLE。郁闷了一整天后发现最耗时的是寻找节点的find()函数。果断改良,用map记录每个节点的地址(指针),在链表初始化的时候就初始化map的键。对于每个要移动的节点,先从链表中删除;然后再新建节点,插入到链表,同时更新map【见代码一】;对于方向,只要记录改变的次数,在操作处理时改变目标节点就可以了;最后计算的时候,直接按照方向从链表头和链表尾逐个编立计数,当计数变量为奇数的时候,累加节点的值,输出累加变量的值即可。
后面突发奇想,干脆不删除节点,直接将拿出来的要改变位置的节点插入到指定节点后面即可,不用更新map,也不必新建和删除节点,可以节约时间。于是就写了【代码二】,改进后的程序运行时间节约了72ms。时间不多,但是,思路更简洁了。改进了冗余部分。
个人感想:
省赛后,一直耿耿于怀,很久没有与AC约会,代码也打得少。快一个月了,回来机房打代码,打了没几行,有种热泪盈眶的感觉。当手指在键盘跳动,心里就是别有一番滋味。突然就想到前段时间去电子电工基地帮忙打文件,有人说“打代码的人就是不一样,敲键盘的节奏就不同”。当时小有感触,但也没放在心上。现在手指在键盘上游走,有种舍不得离开的感觉,就像就别重逢的恋人。说不出的。。。
本来就想着ACM,就这样算了,也奋斗这么久了,人也不小了,就这样吧。现在看来,好像还是放不下,还是不甘心,两年啊!都习以为常了,这种生活方式,这种带着耳机刷代码的感觉,忘不了,放不下。也许我只是累了,等我休息下,又回来了。
感觉的事情,谁说的定呢?
要命的熟悉的感觉,要命的苦涩与喜悦。
记得那些差一题的遗憾,那些独挡两题的兴奋,全然过去了。
还是没能在最后完成自己的愿望。
ACM毁大学,AC毁一生!
说起来都是泪(累)。
不知道能不能就这样算了。不知道能不能就这样放下!
【代码一】
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<map> using namespace std; int n,m; long long ans; struct node //链表节点 { int x; struct node *first; //前驱指针 struct node *next; //后继指针 }*head,*are,*p,*q; map<int,node*> addre; void initial() //创建一个长度为n+2,赋值为1-n的带头结点和尾节点的双向链表 { head=(node *)malloc(sizeof(node)); are=head; head->first=NULL; head->next=NULL; p=head; for(int i=1;i<=n;i++) { q=(node *)malloc(sizeof(node)); p->next=q; q->first=p; q->next=NULL; q->x=i; addre[i]=q; p=q; are=q; } q=(node *)malloc(sizeof(node)); p->next=q; q->first=p; q->next=NULL; are=q; } void gotozero()// 清空链表,释放所有节点,以免超内存 { p=are; while(p!=head) { q=p; p=p->first; free(q); } free(p); addre.clear(); } node* find(int x) //在链表中查找值为x的节点,返回该节点的指针 { p=head->next; while(p->x!=x)p=p->next; return p; } void delet(node* u) //删除指针u指向的节点 { u->first->next=u->next; u->next->first=u->first; free(u); } void insert(node* u,int x)//在指针u指向的节点前面插入一个值为x的节点 { q=(node *)malloc(sizeof(node)); q->x=x; addre[x]=q; q->first=u->first; q->next=u; u->first->next=q; u->first=q; } void cul1() //逆向处理 { int num=1; p=are->first; while(p!=head) { if(num%2==1)ans+=p->x; p=p->first; num++; } } void cul2()//正向处理 { int num=1; p=head->next; while(p!=are) { if(num%2==1)ans+=p->x; p=p->next; num++; } } void output() //将链表按中节点的值按顺序输出 { p=head->next; while(p->next!=NULL)printf("%d ",p->x),p=p->next; printf("\n"); } int main() { int u,x,y; int i,j;int r=1; while(scanf("%d%d",&n,&m)!=EOF) { int flag=0; ans=0; initial(); while(m--) { scanf("%d",&u); if(u==4)flag++; else { scanf("%d%d",&x,&y); if(u==1) { delet(addre[x]); if(flag%2==0)insert(addre[y],x); else insert(addre[y]->next,x); } else if(u==2) { delet(addre[x]); if(flag%2==0)insert(addre[y]->next,x); else insert(addre[y],x); } else { q=addre[x]; p=addre[y]; q->x=y; p->x=x; addre[x]=p; addre[y]=q; } } //output(); } flag%2?cul1():cul2(); printf("Case %d: %lld\n",r++,ans); gotozero(); } return 0; } /************************************************************** Problem: 1329 User: 20114045007 Language: C++ Result: Accepted Time:660 ms Memory:5652 kb ****************************************************************/
【代码二】
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<map> using namespace std; int n,m; long long ans; struct node //链表节点 { int x; struct node *first; //前驱指针 struct node *next; //后继指针 }*head,*are,*p,*q; map<int,node*> addre; void initial() //创建一个长度为n+2,赋值为1-n的带头结点和尾节点的双向链表 { head=(node *)malloc(sizeof(node)); are=head; head->first=NULL; head->next=NULL; p=head; for(int i=1;i<=n;i++) { q=(node *)malloc(sizeof(node)); p->next=q; q->first=p; q->next=NULL; q->x=i; addre[i]=q; p=q; are=q; } q=(node *)malloc(sizeof(node)); p->next=q; q->first=p; q->next=NULL; are=q; } void gotozero()// 清空链表,释放所有节点,以免超内存 { p=are; while(p!=head) { q=p; p=p->first; free(q); } free(p); addre.clear(); } void delet() //删除指针u指向的节点 { q->first->next=q->next; q->next->first=q->first; } void insert(node* u,int x)//在指针u指向的节点前面插入一个值为x的节点 { q->x=x; addre[x]=q; q->first=u->first; q->next=u; u->first->next=q; u->first=q; } void cul1() //逆向处理 { int num=1; p=are->first; while(p!=head) { if(num%2==1)ans+=p->x; p=p->first; num++; } } void cul2()//正向处理 { int num=1; p=head->next; while(p!=are) { if(num%2==1)ans+=p->x; p=p->next; num++; } } int main() { int u,x,y; int i,j;int r=1; while(scanf("%d%d",&n,&m)!=EOF) { int flag=0; ans=0; if(r!=1)gotozero(); initial(); while(m--) { scanf("%d",&u); if(u==4)flag++; else { scanf("%d%d",&x,&y); if(u==1) { q=addre[x]; delet(); if(flag%2==0)insert(addre[y],x); else insert(addre[y]->next,x); } else if(u==2) { q=addre[x]; delet(); if(flag%2==0)insert(addre[y]->next,x); else insert(addre[y],x); } else { q=addre[x]; p=addre[y]; q->x=y; p->x=x; addre[x]=p; addre[y]=q; } } } flag%2?cul1():cul2(); printf("Case %d: %lld\n",r++,ans); } return 0; } /************************************************************** Problem: 1329 User: 20114045007 Language: C++ Result: Accepted Time:588 ms Memory:5652 kb ****************************************************************/