zoukankan      html  css  js  c++  java
  • 【刷题记录】杂题记录

    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
    %d",d2-d1+2*l);
    65     return 0;
    66 }
    View Code
  • 相关阅读:
    学习进度报告2021/4/5
    学习进度报告2021/4/4
    学习进度报告2021/4/3
    学习进度报告2021/4/2
    学习进度报告2021/4/1
    学习进度报告2021/3/31
    《学会提问》读书笔记3
    学习进度报告2021/3/30
    MySQL入门——如何进行主从配置
    MySQL入门详解——事务、锁、优化
  • 原文地址:https://www.cnblogs.com/zsnuo/p/7498679.html
Copyright © 2011-2022 走看看