一行盒子
题意理解:
给一行数字(给出个数,从小到大从做到右排列),经过一些变化后,输出其顺序排在奇数位置上的数的和。
一个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
****************************************************************/