codevs 1743 反转卡片

题目描述 Description

【dzy493941464|yywyzdzr原创】

小A将N张卡片整齐地排成一排,其中每张卡片上写了1~N的一个整数,每张卡片上的数各不相同。

比如下图是N=5的一种情况:3 4 2 1 5

接下来你需要按小A的要求反转卡片,使得左数第一张卡片上的数字是1。操作方法:令左数第一张卡片上的数是K,如果K=1则停止操作,否则将左数第1~K张卡片反转。

第一次(K=3)反转后得到:2 4 3 1 5

第二次(K=2)反转后得到:4 2 3 1 5

第三次(K=4)反转后得到:1 3 2 4 5

可见反转3次后,左数第一张卡片上的数变成了1,操作停止。

你的任务是,对于一种排列情况,计算要反转的次数。你可以假设小A不会让你操作超过100000次。

输入描述 Input Description

第1行一个整数N

第2行N个整数,为1~N的一个全排列。

输出描述 Output Description

仅1行,输出一个整数表示要操作的次数。

如果经过有限次操作仍无法满足要求,输出-1。

样例输入 Sample Input

5

3 4 2 1 5

样例输出 Sample Output

3

数据范围及提示 Data Size & Hint

0<N≤300,000。

splay翻转裸题,又调了一个下午

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 const int N=300010;
 5 int size[N],c[N][2],rev[N],fa[N],id[N],a[N];
 6 int n,rt;
 7 void pushup(int k){
 8     int l=c[k][0],r=c[k][1];
 9     size[k]=size[l]+size[r]+1;
10 }
11
12 void pushdown(int k){
13     if (rev[k]){
14         int l=c[k][0],r=c[k][1];
15         swap(c[k][1],c[k][0]);
16         rev[l]^=1;rev[r]^=1;
17         rev[k]=0;//第一次k打成l,wa
18     }
19 }
20
21 void rotate(int x,int &k){
22     int y=fa[x],z=fa[y],l,r;
23     if (c[y][0]==x)l=0;else l=1;r=l^1;
24     if (y==k)k=x;
25     else if (c[z][0]==y)c[z][0]=x; else c[z][1]=x;
26     fa[c[x][r]]=y; fa[x]=z; fa[y]=x;
27     c[y][l]=c[x][r];c[x][r]=y;
28     pushup(y);pushup(x);
29 }
30
31 void splay(int x,int &k){
32     while (x!=k){//忘记打这一句 wa*2
33         int y=fa[x],z=fa[y];
34         if (y!=k){
35             if (c[z][0]==y^c[y][0]==x) rotate(x,k);
36             else rotate(y,k);
37         }
38         rotate(x,k);
39     }
40 }
41
42 void build(int l,int r,int f)
43 {
44     if(l>r)return;
45     int mid=(l+r)>>1;
46     if(mid<f)c[f][0]=mid;//这句写错了 wa*3
47     else c[f][1]=mid;
48     size[mid]=1;fa[mid]=f;
49     if(l==r)return;
50     build(l,mid-1,mid);build(mid+1,r,mid);
51     pushup(mid);
52 }
53
54 int find(int x,int rk){
55     pushdown(x);
56     int l=c[x][0],r=c[x][1];
57     if (size[l]+1==rk) return x;
58     if (size[l]>=rk) return find(l,rk);
59     return find(r,rk-size[l]-1);
60 }
61
62 void rever(int l,int r){
63     int x=find(rt,l),y=find(rt,r+2);
64     splay(x,rt); splay(y,c[x][1]);
65     int z=c[y][0];//这句写错了wa*4
66     rev[z]^=1;
67 }
68
69 int main(){
70     scanf("%d",&n);
71     for (int i=2;i<=n+1;i++) scanf("%d",&a[i]);
72     for (int i=1;i<=n+2;i++) id[i]=i;
73     build(1,n+2,0); rt=(n+3)>>1;
74     int sum=0;
75     bool flag=0;
76     while (sum<=100000){
77         int mid=a[find(rt,2)];
78         if (mid==1){
79             flag=1;
80             break;
81         }
82         sum++;
83         rever(1,mid);
84     }
85     if (flag) printf("%d",sum);
86     else printf("-1");
87 }
时间: 2024-12-15 02:06:00

codevs 1743 反转卡片的相关文章

codevs 1743 反转卡片 rope or splay

[codevs1743]反转卡片 题目描述 Description [dzy493941464|yywyzdzr原创] 小A将N张卡片整齐地排成一排,其中每张卡片上写了1~N的一个整数,每张卡片上的数各不相同. 比如下图是N=5的一种情况:3 4 2 1 5 接下来你需要按小A的要求反转卡片,使得左数第一张卡片上的数字是1.操作方法:令左数第一张卡片上的数是K,如果K=1则停止操作,否则将左数第1~K张卡片反转. 第一次(K=3)反转后得到:2 4 3 1 5 第二次(K=2)反转后得到:4 2

CodeVS1743 反转卡片

传送门 splay裸裸哒区间翻转维护,月考考跪装作很开心的样子 直接贴代码. 1 //CodeVS 2 //by Cydiater 3 //2016.9.11 4 #include <iostream> 5 #include <cstring> 6 #include <string> 7 #include <algorithm> 8 #include <queue> 9 #include <map> 10 #include <c

总结-数据结构

数据结构 1. 树状数组 写起来很方便, 用的比较多, 比线段树更实用吧. 虽然原理到现在不太清楚... 往往没有裸树状数组的题目, 往往和其他算法相结合. 单次修改或查询: O(logn) 1. BZOJ-2716-天使玩偶angel-CDQ分治 cdq分治 2. BZOJ-1878-HH的项链-SDOI2009 离线处理, 求种数 3. BZOJ-3289-Mato的文件管理-莫队+树状数组 莫队, 用树状数组统计逆序对 树状数组的弱点是不支持区间最大最小值什么的, 但是利用它可以统计前缀和

Splay复习

CODEVS 1743 翻转卡片 小A将N张卡片整齐地排成一排,其中每张卡片上写了1~N的一个整数,每张卡片上的数各不相同. 比如下图是N=5的一种情况:3 4 2 1 5 接下来你需要按小A的要求反转卡片,使得左数第一张卡片上的数字是1.操作方法:令左数第一张卡片上的数是K,如果K=1则停止操作,否则将左数第1~K张卡片反转. 第一次(K=3)反转后得到:2 4 3 1 5 第二次(K=2)反转后得到:4 2 3 1 5 第三次(K=4)反转后得到:1 3 2 4 5 可见反转3次后,左数第一

计划做题列表

估计是做不完.. emmmm  不用估计,是肯定 马上就滚回去学文化课了.... ....列表全都是数据结构... mdzz 我可能是傻了 1.数学  P1214 [USACO1.4]等差数列 Arithmetic Progressions https://www.luogu.org/problemnew/show/P1214 2.P4243 [JSOI2009]等差数列 线段树 https://www.luogu.org/problemnew/show/P4243 主席树 P3313 [SDO

●Splay的一些题

●个人感觉: 代码长: 函数多: (很套路): (很强的Splay,无愧于"区间王") ●NOI2005维修数列 一个可以当模板学习的题,包含了众多操作(函数): 区间插入,删除,更新,翻转,询问信息以及"回收空间"(名字很刚)等. update()pushdown() rotate() splay() build() find() split() insert() rec() erase() query() rever() modify()还有main() 建议初

伸展树复习

T1 郁闷的出纳员 一个数据结构,支持单点插入.删除几个不一定连续的点.查询k值操作 初做:2017.2.18   time:1268ms    memory:3MB http://www.cnblogs.com/TheRoadToTheGold/p/6412790.html 现在:2017.3.28   time:570ms   memory:3MB 初做时直接套模板,删除分5种情况, 本题实际只需3种情况 这一次的查询用递归写的 int query(int now,int k) { int

【集训第四天&#183;继续刷题】之 lgh怒刚ypj

继续水题,终于完全掌握了伸展树了,好心痛QAQ. 1.codevs1343 蚱蜢 区间最大值查询+单点移动 最大值查询维护一个mx数组就行,单点移动么,先删除在插入 CODE: 1 /* 2 PS: 比较max值时,要写成 mx[x]=max(a[x],max(mx[l],mx[r]));形式 3 且最好把mx[0]赋值为负无穷大 4 5 取max时,注意初值问题 6 7 */ 8 9 #include<bits/stdc++.h> 10 #define N 100005 11 using n

IOIOI卡片占卜(Atcoder-IOIOI カード占い)(最短路)

题目描述: K 理事長は占いが好きで,いつも様々な占いをしている.今日は,表の面に 'I' が,裏の面に 'O' が書か れたカードを使って今年の IOI での日本選手団の出来を占うことにした. 占いの方法は次のようなものである. 1. まず,正の整数 A, B,C, D, E を決める. 2. A + B + C + D + E 枚のカードを横 1 列に並べる.このとき,左から A 枚は表,続く B 枚は裏,続く C 枚は表,続く D 枚は裏,続く E 枚は表にして並べる.このように並べると,