题意翻译
你在输入文章的时候,键盘上的Home键和End键出了问题,会不定时的按下。你却不知道此问题,而是专心致志地打稿子,甚至显示器都没开。当你打开显示器之后,展现你面前的数一段悲剧文本。你的任务是在显示器打开前计算出这段悲剧的文本。 给你一段按键的文本,其中'['表示Home键,']'表示End键,输入结束标志是文件结束符(EOF)。
输出一行,即这段悲剧文本。 翻译贡献者UID:71371
输入输出样例
输入
This_is_a_[Beiju]_text
[[]][][]Happy_Birthday_to_Tsinghua_University
输出
BeijuThis_is_a__text
Happy_Birthday_to_Tsinghua_University
#include
using namespace std;
struct node
{ char val;
node *next;
} *head, *tail, *now;
int main ()
{ char s[100086];
while (scanf("%s", s) != EOF)
{ head = tail = now = new node;
head->next = tail->next = now->next = NULL;
int str = strlen(s);
for (int i = 0; i < str; i++)
{ if (s[i] == '[') now = head;
else if (s[i] == ']') now = tail;
else
{ node *tmp = new node;
tmp->val = s[i], tmp->next = now->next;
now->next = tmp;
now = tmp;
if (now->next == NULL)tail = now;
}
}
for (now = head->next; now != NULL; now = now->next)
printf("%c", now->val);
puts("");
}
return 0;
}
题意翻译
你有n个盒子在桌子上的一条线上从左到右编号为1……n。你的任务是模拟四种操作
1 X Y 移动盒子编号X到盒子编号Y的左边(如果X已经在Y的左边了就忽略)
2 X Y 移动盒子编号X到盒子编号Y的右边(如果X已经在Y的右边了就忽略)
3 X Y 交换盒子编号X与盒子编号Y的位置
4 将整条线反转
操作保证合法,X不等于Y
举一个例子,如果n=6,操作 1 1 4然后就变成了2 3 1 4 5 6;再操作 2 3 5就变成了 2 1 4 5 3 6;再操作 3 1 6 就变成 2 6 4 5 3 1;最后操作4,就变成了 1 3 5 4 6 2
输入
最多有10组数据,每个数据会包含两个整数n,m(1≤n,m<100,000), 接下来是m行数据,表示操作。
输出
对于每组数据,输出他们奇数位置的编号的和。
输入输出样例
输入
6 4 1 1 4 2 3 5 3 1 6 4 6 3 1 1 4 2 3 5 3 1 6 100000 1 4
输出
Case 1: 12 Case 2: 9 Case 3: 2500050000
用链表实现
#include
using namespace std;
struct node
{ int data;
node *next;
};
int n,m,id;
node *zhi[100005];
bool flag;
int main()
{ while(scanf("%d%d",&n,&m)!=EOF)
{ ++id;//第几组数据,输出时用
flag=1;//顺序正序,0则为倒序
node *head=new node;//新的head
head->next=NULL;//初值
node *ptr=head;//记录上一个指针
for(int i=1;i<=n;++i)
{ node *p=new node;//新的指针
p->next=NULL;//目前下一个为空
p->data=i;//数为i
ptr->next=p;//上一个数的next指向p
zhi[i]=ptr;//这个数的上一个数的指针为ptr
ptr=p;//更新ptr
}
for(int i=1;i<=m;++i)
{ int k,x,y;
scanf("%d",&k);
if(!flag&&(k==1||k==2))//如果倒序又是与左右有关系
k=3-k;//交换
if(k==1)
{ scanf("%d%d",&x,&y);
node *p=zhi[x]->next;
zhi[x]->next=zhi[x]->next->next;
if(zhi[x]->next)
zhi[zhi[x]->next->data]=zhi[x];
/*删掉x的位置*/
p->next=zhi[y]->next;
zhi[y]->next=p;
zhi[x]=zhi[y];
zhi[p->next->data]=p;
/*把x放到y的左边*/
}
else if(k==2)
{
scanf("%d%d",&x,&y);
node *p=zhi[x]->next;
zhi[x]->next=zhi[x]->next->next;
if(zhi[x]->next)
zhi[zhi[x]->next->data]=zhi[x];
/*删掉x的位置*/
p->next=zhi[y]->next->next;
zhi[y]->next->next=p;
zhi[x]=zhi[y]->next;
if(p->next)
zhi[p->next->data]=p;
/*把x放到y的右边*/
}
else if(k==3)
{ scanf("%d%d",&x,&y);
if(zhi[y]->next==zhi[x])//x是y的下一个,方便起见交换一下,反正没有顺序
swap(x,y);
if(zhi[x]->next==zhi[y])//相邻
{ node *p=zhi[x]->next,*q=zhi[y]->next;
zhi[x]->next=q;
p->next=q->next;
q->next=p;
zhi[y]=zhi[x];
zhi[x]=q;
if(p->next)
zhi[p->next->data]=p;
}
else//不相邻
{ node *p=zhi[x]->next,*q=zhi[y]->next,*p1=p->next,*q1=q->next;
zhi[x]->next=q,q->next=p1;
zhi[y]->next=p,p->next=q1;;
node *t=zhi[y];
zhi[y]=zhi[x];
zhi[x]=t;
if(p1) zhi[p1->data]=q;
if(q1) zhi[q1->data]=p;
}
}
else//反转
flag=!flag;
}
bool ji=0;
long long sum=0;//记得开long long哦
ptr=head;
for(node *i=head->next;i;i=i->next)
{
ji=!ji;
if(n%2&&ji)//n为奇数,第奇数个
sum+=i->data;
else if(!(n%2)&&flag&&ji)//n为偶数,第奇数个,反转偶数次
sum+=i->data;
else if(!(n%2)&&!flag&&!ji)//n为偶数,第偶数个,反转奇数次
sum+=i->data;
delete ptr;//防止内存泄漏,删了!
ptr=i;//更新ptr
}
delete ptr;//最后一个还没删,删了!
printf("Case %d: %lld\n",id,sum);//输出
}
return 0;
}
用数组模拟
#include
using namespace std;
int ri[100005], le[100005];
int link(int l, int r)
{ ri[l] = r;
le[r] = l;
}
int main()
{ int n, m, cases = 1;
while(scanf("%d%d", &n, &m) != EOF)
{ int i, sta = 0;
ri[n] = 0;
le[0] = n;
for(i = 0; i < n; i++) link(i, i+1);
for(i = 1; i <= m; i++)
{ int p, x, y;
scanf("%d", &p);
if(p == 4) sta = !sta;
else
{ scanf("%d%d", &x, &y);
if(p == 3 && ri[y] == x) swap(x, y);
if(sta && (p == 1 || p == 2)) p = 3 - p;
if(p == 1 && ri[x] == y) continue;
if(p == 2 && ri[y] == x) continue;
}
int lx = le[x], rx = ri[x], ly = le[y], ry = ri[y];
switch (p)
{ case 1 :
{ link(lx, rx);
link(ly, x);
link(x, y);
break;
}
case 2 :
{ link(lx, rx);
link(x, ry);
link(y, x);
break;
}
case 3 :
{ link(lx, y);
link(x, ry);
if(rx == y) link(y, x);
else{link(y, rx);link(ly, x);}
break;
}
default : break;
}
}
long long ans = 0;
int b = 0;
for(i = 1; i <= n; i++)
{ b = ri[b];
if(i % 2 == 1) ans += b;
}
if(sta && n % 2 == 0) ans = (long long)n * (n + 1) / 2 - ans;
printf("Case %d: %lld\n", cases++, ans);
}
return 0;
}
题目描述
小熊的水果店里摆放着一排 n 个水果。每个水果只可能是苹果或桔子,从左到右依次用正整数 1,2,…,n 编号。连续排在一起的同一种水果称为一个“块”。小熊要把这一排水果挑到若干个果篮里,具体方法是:每次都把每一个“块”中最左边的水果同时挑出,组成一个果篮。重复这一操作,直至水果用完。注意,每次挑完一个果篮后,“块”可能会发生变化。比如两个苹果“块”之间的唯一桔子被挑走后,两个苹果“块”就变成了一个“块”。请帮小熊计算每个果篮里包含的水果。
输入格式
第一行,包含一个正整数 n,表示水果的数量。
第二行,包含 n 个空格分隔的整数,其中第 i 个数表示编号为 i 的水果的种类,1 代表苹果,0 代表桔子。
输出格式
输出若干行。
第 i 行表示第 i 次挑出的水果组成的果篮。从小到大排序输出该果篮中所有水果的编号,每两个编号之间用一个空格分隔。
输入输出样例
输入
12 1 1 0 0 1 1 1 0 1 1 0 0
输出
1 3 5 8 9 11 2 4 6 12 7 10
输入
20 1 1 1 1 0 0 0 1 1 1 0 0 1 0 1 1 0 0 0 0
输出
1 5 8 11 13 14 15 17 2 6 9 12 16 18 3 7 10 19 4 20
输入
见附件中的 fruit/fruit3.in。
输出
见附件中的 fruit/fruit3.ans。
【样例解释 #1】
这是第一组数据的样例说明。
所有水果一开始的情况是 [1,1,0,0,1,1,1,0,1,1,0,0],一共有 6 个块。
在第一次挑水果组成果篮的过程中,编号为 1,3,5,8,9,11 的水果被挑了出来。
之后剩下的水果是 [1,0,1,1,1,0],一共 4 个块。
在第二次挑水果组成果篮的过程中,编号为2,4,6,12 的水果被挑了出来。
之后剩下的水果是 [1,1],只有 1 个块。
在第三次挑水果组成果篮的过程中,编号为 7 的水果被挑了出来。
最后剩下的水果是 [1],只有 1个块。
在第四次挑水果组成果篮的过程中,编号为 10 的水果被挑了出来。
【数据范围】
对于 10% 的数据,n≤5。
对于 30% 的数据,n≤1000。
对于 70% 的数据,n≤50000。
对于 100% 的数据,1≤n≤2×10^5。
【提示】
由于数据规模较大,建议 C/C++ 选手使用 scanf
和 printf
语句输入、输出。
#include
#define MAXN 200100
using namespace std;
int n, a[MAXN], l[MAXN], r[MAXN];
vector b;
int main()
{ scanf("%d", &n);
a[0] = a[n + 1] = -1, r[0] = 1, l[n + 1] = n;
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
if (a[i] != a[i - 1]) b.push_back(i);
l[i] = i - 1, r[i] = i + 1;
}
while (r[0] != n + 1) {
vector tmp;
for (int i = 0; i < b.size(); i++) {
printf("%d ", b[i]);
int u = l[b[i]], v = r[b[i]];
r[u] = v, l[v] = u;
if (a[b[i]] != a[u] && a[b[i]] == a[v]) tmp.push_back(v);
}
puts("");
b = tmp;
}
return 0;
}