反转链表时间开销太大,其实不需要反转只需要记录反转操作的次数即可,若最后次数为偶数,则从左往右加;若为奇数,则从右往左加。开始用指针链表超时,我以为是动态分配空间太慢,换数组链表还是超时,后来想到可能是忽略了特殊情况,看书后发现没有考虑到xy相邻的情况。。。还有就是如果不用判断到底从哪边加,因为计算机组成结构告诉我们分支结构的跳转太浪费时间,如果是翻转次数为奇数的话而且N为偶数的话拿总和去减奇数和即可。
version 1(指针链表,超时):
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100000 + 5;
int n,m;
struct node{
int num;
struct node *left;
struct node *right;
};
node* d[maxn];
int main(){
freopen("data.in","r",stdin);
freopen("data.out","w",stdout);
int kase = 0;
while(scanf("%d %d",&n,&m) == 2){
node* l = new node;
node* r = new node;
l->num = r->num = 0;
node* a = l;
for(int i = 1;i <= n;i++){
node* t = new node;
t->num = i;
a->right = t;
t->left = a;
d[i] = a = t;
}
d[n]->right = r;
r->left = d[n];
int cmd,x,y;
int mark = 0;
while(m--){
scanf("%d",&cmd);
if(cmd == 1 || cmd == 2){
scanf("%d %d",&x,&y);
d[x]->left->right = d[x]->right;
d[x]->right->left = d[x]->left;
}
if(cmd == 1){
d[x]->right = d[y];
d[x]->left = d[y]->left;
d[y]->left->right = d[x];
d[y]->left = d[x];
}
else if(cmd == 2){
d[x]->left = d[y];
d[x]->right = d[y]->right;
d[y]->right->left = d[x];
d[y]->right = d[x];
}
else if(cmd == 3){
scanf("%d %d",&x,&y);
node* t1 = d[x]->left;
node* t2 = d[x]->right;
d[x]->left = d[y]->left;
d[y]->left->right = d[x];
d[x]->right = d[y]->right;
d[y]->right->left = d[x];
d[y]->left = t1;
t1->right = d[y];
d[y]->right = t2;
t2->left = d[y];
}
else mark = (mark+1)%2;
}
long long Sum = 0,odd = 1;
if(!mark){
while(l->right->num){
if(odd++%2) Sum += l->right->num;
l = l->right;
}
}
else{
while(r->left->num){
if(odd++%2) Sum += r->left->num;
r = r->left;
}
}
printf("Case %d: %lld\n",++kase,Sum);
}
return 0;
}
version 2(数组链表,超时):
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100000 + 5;
int n,m;
int Left[maxn],Right[maxn];
void link(int l,int r){
Left[r] = l;
Right[l] = r;
}
int main(){
// freopen("data.in","r",stdin);
// freopen("data.out","w",stdout);
int kase = 0;
while(scanf("%d %d",&n,&m) == 2){
int cmd,x,y;
int mark = 0,l = 0,r = n+1;
for(int i = 0;i <= n;i++){
link(i,i+1);
}
while(m--){
scanf("%d",&cmd);
if(cmd == 1 || cmd == 2){
scanf("%d %d",&x,&y);
link(Left[x],Right[x]);
}
if(cmd == 1){
link(Left[y],x);
link(x,y);
}
else if(cmd == 2){
link(x,Right[y]);
link(y,x);
}
else if(cmd == 3){
scanf("%d %d",&x,&y);
int t1 = Left[x],t2 = Right[x];
link(Left[y],x);
link(x,Right[y]);
link(t1,y);
link(y,t2);
}
else mark = (mark+1)%2;
}
long long Sum = 0,odd = 1;
if(mark){
while(Left[r]){
if(odd++%2) Sum += Left[r];
r = Left[r];
}
}
else{
while(Right[l] != n+1){
if(odd++%2) Sum += Right[l];
l = Right[l];
}
}
printf("Case %d: %lld\n",++kase,Sum);
}
return 0;
}
version 3(110ms):
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100000 + 5;
int n,m;
int Left[maxn],Right[maxn];
void link(int l,int r){
Left[r] = l;
Right[l] = r;
}
int main(){
// freopen("data.in","r",stdin);
// freopen("data.out","w",stdout);
int kase = 0;
while(scanf("%d %d",&n,&m) == 2){
int cmd,x,y;
int mark = 0,l = 0,r = n+1;
for(int i = 0;i <= n;i++){
link(i,i+1);
}
while(m--){
scanf("%d",&cmd);
if(cmd == 1 || cmd == 2){
if(mark) cmd = 3 - cmd;
scanf("%d %d",&x,&y);
}
if(cmd == 1){
if(x == Left[y]) continue;
link(Left[x],Right[x]);
link(Left[y],x);
link(x,y);
}
else if(cmd == 2){
if(x == Right[y]) continue;
link(Left[x],Right[x]);
link(x,Right[y]);
link(y,x);
}
else if(cmd == 3){
scanf("%d %d",&x,&y);
if(Right[y] == x) swap(x,y);
int t1 = Left[x],t2 = Right[x];
if(x == Left[y]){
link(x,Right[y]);
link(Left[x],y);
link(y,x);
}
else{
link(Left[y],x);
link(x,Right[y]);
link(t1,y);
link(y,t2);
}
}
else mark = (mark+1)%2;
}
long long Sum = 0,odd = 1;
if(mark){
while(Left[r]){
if(odd++%2) Sum += Left[r];
r = Left[r];
}
}
else{
while(Right[l] != n+1){
if(odd++%2) Sum += Right[l];
l = Right[l];
}
}
printf("Case %d: %lld\n",++kase,Sum);
}
return 0;
}
version 3(参考书上代码,80ms):
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100000 + 5;
int n,m;
int Left[maxn],Right[maxn];
void link(int l,int r){
Left[r] = l;
Right[l] = r;
}
int main(){
// freopen("data.in","r",stdin);
// freopen("data.out","w",stdout);
int kase = 0;
while(scanf("%d %d",&n,&m) == 2){
int cmd,x,y;
int mark = 0,l = 0;
for(int i = 0;i <= n;i++){
link(i,i+1);
}
while(m--){
scanf("%d",&cmd);
if(cmd == 4) mark = !mark;
else{
scanf("%d %d",&x,&y);
if(cmd == 3 && Right[y] == x) swap(x,y);
if(cmd != 3 && mark) cmd = 3 - cmd; //后两句要放后面。。
if(cmd == 1 && Left[y] == x) continue;
if(cmd == 2 && Right[y] == x) continue;
int lx = Left[x],rx = Right[x],ly = Left[y],ry = Right[y];
if(cmd == 1){
link(lx,rx); link(ly,x); link(x,y);
}
else if(cmd == 2){
link(lx,rx); link(x,ry); link(y,x);
}
else if(cmd == 3){
if(x == ly){
link(x,ry); link(lx,y); link(y,x);
}
else{
link(ly,x); link(x,ry); link(lx,y); link(y,rx);
}
}
}
}
long long Sum = 0,odd = 1;
while(Right[l] != n+1){
if(odd++%2) Sum += Right[l];
l = Right[l];
}
if(mark && n%2 == 0) Sum = (long long)n*(n+1)/2 - Sum; //奇数的话两边数都一样的
printf("Case %d: %lld\n",++kase,Sum);
}
return 0;
}