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