码迷,mamicode.com
首页 > 其他好文 > 详细

【刷题记录】杂题记录

时间:2018-04-20 00:10:56      阅读:152      评论:0      收藏:0      [点我收藏+]

标签:font   main   完成   isp   node   open   false   排序   for   

1.【bzoj 4552】[Tjoi2016&Heoi2016]排序

题意:给出一个1到n的全排列,现在对这个全排列序列进行m次局部排序。排序分为两种:(0,l,r)表示将区间[l,r]的数字升序排序;(1,l,r)表示将区间[l,r]的数字降序排序。最后询问第q位置上的数字。

分析:二分答案,将所有值小于等于当前值的数赋为0,其余赋为1。利用线段树可以通过统计区间内数字1的个数来使当前区间有序。进行m次局部排序后可以得到答案与当前值的大小关系,满足可二分性。

技术分享图片
 1 #include<cstdio> 
 2 #include<algorithm>
 3 #include<cstring>
 4 #define l(x) x<<1
 5 #define r(x) x<<1|1
 6 using namespace std;
 7 const int N=1e5+10;
 8 int n,m,now,L,R,pos,ans,sum;
 9 int a[N],t[N*4],tag[N*4];
10 struct node{int op,l,r;}b[N];
11 int read()
12 {
13     int x=0,f=1;char c=getchar();
14     while(c<0||c>9){if(c==-)f=-1;c=getchar();}
15     while(c>=0&&c<=9){x=x*10+c-0;c=getchar();}
16     return x*f;
17 }
18 void up(int x){t[x]=t[l(x)]+t[r(x)];}
19 void dn(int x,int l,int r)
20 {
21     int mid=(l+r)>>1;
22     tag[l(x)]=tag[x];t[l(x)]=tag[x]*(mid-l+1);
23     tag[r(x)]=tag[x];t[r(x)]=tag[x]*(r-mid);
24     tag[x]=-1;
25 }
26 void build(int x,int l,int r)
27 {
28     tag[x]=-1;
29     if(l==r){t[x]=(a[l]>now);return;}
30     int mid=(l+r)>>1;
31     build(l(x),l,mid);
32     build(r(x),mid+1,r);
33     up(x);
34 }
35 void change(int x,int l,int r,int p)
36 {
37     if(l!=r&&tag[x]!=-1)dn(x,l,r);
38     if(L<=l&&R>=r){tag[x]=p;t[x]=p*(r-l+1);return;}
39     int mid=(l+r)>>1;
40     if(L<=mid)change(l(x),l,mid,p);
41     if(R>mid)change(r(x),mid+1,r,p);
42     if(l!=r)up(x);
43 }
44 void ask(int x,int l,int r)
45 {
46     if(l!=r&&tag[x]!=-1)dn(x,l,r);
47     if(L<=l&&R>=r){sum+=t[x];return;}
48     int mid=(l+r)>>1;
49     if(L<=mid)ask(l(x),l,mid);
50     if(R>mid)ask(r(x),mid+1,r);
51 }
52 int main()
53 {
54     n=read();m=read();
55     for(int i=1;i<=n;i++)a[i]=read();
56     for(int i=1;i<=m;i++)
57         b[i].op=read(),b[i].l=read(),b[i].r=read();
58     pos=read();
59     int l=1,r=n;
60     while(l<=r)
61     {
62         now=(l+r)>>1;build(1,1,n);
63         for(int i=1;i<=m;i++)
64         {
65             L=b[i].l;R=b[i].r;
66             sum=0;ask(1,1,n);
67             if(!b[i].op)sum=b[i].r-b[i].l+1-sum;
68             L=b[i].l;R=b[i].l+sum-1;
69             if(L<=R)change(1,1,n,b[i].op);
70             L=b[i].l+sum;R=b[i].r;
71             if(L<=R)change(1,1,n,1-b[i].op);
72         }
73         L=R=pos;sum=0;ask(1,1,n);
74         if(sum)l=now+1;
75         else ans=now,r=now-1;
76     }
77     printf("%d",ans);
78     return 0;
79 }
View Code

2.【bzoj 2144】跳跳棋

题意:棋盘上有3颗棋子,分别在a,b,c位置,目标是通过最少的跳动把他们的位置移成x,y,z。跳动的规则即为任意选一颗棋子,对一颗中轴棋子跳动,跳动后两颗棋子距离不变。一次只允许跳过1颗棋子。首先判断是否可以完成任务;如果可以,输出最少需要的跳动次数。

分析:中间的棋子可以往两侧跳,但两侧的棋子只有一个能往中间跳(跟中间棋子距离较小的那一个)。那么所有的状态就能表示为一棵二叉树,在树上往下走即为中间向两边跳。问题转换为给定树上的两个结点,求其距离。在当前状态在树上往上走的过程中利用了辗转相除的思想。

技术分享图片
 1 #include<cstdio> 
 2 #include<algorithm>
 3 #include<cstring>
 4 using namespace std;
 5 const int inf=1e9;
 6 int tmp,d1,d2,ans,a[4],b[4];
 7 struct node{int x[4];}t1,t2;
 8 int read()
 9 {
10     int x=0,f=1;char c=getchar();
11     while(c<0||c>9){if(c==-)f=-1;c=getchar();}
12     while(c>=0&&c<=9){x=x*10+c-0;c=getchar();}
13     return x*f;
14 }
15 node calc(int *a,int k)//两边向中间跳k次,即在树上往上走k步 
16 {
17     node ans;
18     int t1=a[2]-a[1],t2=a[3]-a[2];
19     for(int i=1;i<=3;i++)ans.x[i]=a[i];
20     if(t1==t2)return ans;
21     if(t1<t2)//左边往中间跳 
22     {
23         int t=min(k,(t2-1)/t1);
24         k-=t;tmp+=t;//tmp记录深度,即实际步数 
25         ans.x[2]+=t*t1;ans.x[1]+=t*t1; 
26     }
27     else//右边往中间跳 
28     {
29         int t=min(k,(t1-1)/t2);
30         k-=t;tmp+=t;
31         ans.x[2]-=t*t2;ans.x[3]-=t*t2;
32     }
33     if(k)return calc(ans.x,k);//辗转相除
34     return ans; 
35 }
36 bool operator != (node a,node b)
37 {
38     for(int i=1;i<=3;i++)
39         if(a.x[i]!=b.x[i])return true;
40     return false;
41 }
42 int main()
43 {
44     for(int i=1;i<=3;i++)a[i]=read();
45     for(int i=1;i<=3;i++)b[i]=read();
46     sort(a+1,a+4);sort(b+1,b+4);
47     t1=calc(a,inf);d1=tmp;tmp=0;
48     t2=calc(b,inf);d2=tmp;tmp=0;
49     if(t1!=t2){printf("NO");return 0;}
50     if(d1>d2)
51     {
52         swap(d1,d2);
53         for(int i=1;i<=3;i++)swap(a[i],b[i]);
54     }
55     t2=calc(b,d2-d1);
56     for(int i=1;i<=3;i++)b[i]=t2.x[i];//调整到同一深度 
57     int l=0,r=d1,mid;
58     while(l<=r)
59     {
60         mid=(l+r)>>1;
61         if(calc(a,mid)!=calc(b,mid))l=mid+1;
62         else r=mid-1;
63     }
64     printf("YES\n%d",d2-d1+2*l);
65     return 0;
66 }
View Code

 

【刷题记录】杂题记录

标签:font   main   完成   isp   node   open   false   排序   for   

原文地址:https://www.cnblogs.com/zsnuo/p/7498679.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!