一行盒子
題意理解:
給一行數字(給出個數,從小到大從做到右排列),經過一些變化後,輸出其順序排在奇數位置上的數的和。
一個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 ****************************************************************/