【刷题记录】杂题记录

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 }

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 }

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

时间: 2024-10-07 05:21:26

【刷题记录】杂题记录的相关文章

poj 杂题 - 1959 Darts

这一题放在杂题里,是因为我没有用DP,而是使用的枚举,当然是受到了discuss里面的启发. 因为我们只能有三次机会,每一次只可以是固定的63个数,所以枚举感觉更加直观,但是不知道是不是没有DP快. #include<stdio.h> #include<string.h> int n; int Darts[63]; int main(){ int t,c=1,i,j,k,res; scanf("%d",&t); for(i = 0 ;i<=20;i

2.1【欢乐向】逆向刷题被虐哭日常记录

2.1[欢乐向]逆向刷题被虐哭日常记录 前面好多题之前做了也没记录,懒得整了,直接从剩下的几个开始: Getit 这一段是解密的关键,后面的是把flag写入文档又给删了. 其实可以修改程序逻辑让他别删,但是我不会. ? 逆着来推一边,不会写py,用c写个. ? ? ?不应当,我大概是忘了加括号. ? ???我觉得我的没啥问题,去网上查了查相关的: ? ? ? 在IDA里没看到有S,咱也不知道咋回事. ? ? ? ? ? no-strings-attached 直接扔IDA瞅瞅: ? ? 挨个函数

poj水题-1579 将递归记录会变快

短平快递归肯定卡死,这里需要了解一个情况. 1.递归是否在很多情况再做重复工作? 2.由递归生成的“大面积数据”是否是由“小范围数据”组合而来? 如果都回答“是”.就强烈推荐“记笔记方式”.如果有笔记记录,那么查笔记,否则递归. #include <stdio.h> long s[21][21][21] = {0}; int w(int a,int b,int c) { if (a <= 0 || b <= 0 || c <= 0) return s[0][0][0]=1;

hdu 4961 数学杂题

http://acm.hdu.edu.cn/showproblem.php?pid=4961 先贴个O(nsqrtn)求1-n所有数的所有约数的代码: vector<int>divs[MAXN]; void caldivs() { for(int i=1;i<MAXN;i++) for(int j=i;j<MAXN;j+=i) divs[j].push_back(i); } 有了这个当时理下思路就可写了,但是重复数处理注意: 1.用一个数组vis[]  vis[i]=1表示i存在

5.30杂题选讲

前三题为水题,后面两题更有意思. 然而代码全都咕咕咕了,也许以后会补. Hdu1520 Anniversary party 简单树形DP. Hdu6386 Age of Moyu 简单最短路. bzoj3679 数字之积 简单数位DP. CF Gym 101482G Gathering 首先对于每个点,可行的区域显然是个矩形,那么可以先对这些矩形求交,得到合法区域. 如果不考虑限制,那么最优点显然是\(x,y\)的中位数. 考虑限制之后,只要定下\(x\),那么最优的\(y\)也是确定的. 而且

【最小生成树杂题】

这里谈一下最小生成树 生成树的概念:连通图G的一个子图如果是一棵包含G的所有顶点的树,则该子图称为G的生成树.生成树是连通图的极小连通子图.所谓极小是指:若在树中任意增加一条边,则将出现一个回路:若去掉一条边,将会使之变成非连通图. 生成树各边的权值总和称为生成树的权.权最小的生成树称为最小生成树. 最小生成树一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边.常用于求最小生成树得算法包括kruskal(克鲁斯卡尔)算法或Prim(

_杂题_

杂题集 是个放题的好地方! **** 5.28 **** - BZOJ [3052] 糖果公园 - 据说是一道区间操作的综合题,但现在貌似蹦了? 现在还是太水,之后再来写吧. *************

[杂题]URAL1822. Hugo II&#39;s War

看懂题意的请直接跳过下一坨! 本人有表达障碍! ========================================== 题意: (题意真的很难很难懂啊!!!  去他娘的**) 有一个王国,王国里有一个国王(编号为1),他有(编号为2~n) n-1个臣子(这些臣子并不全和他有直接关系) 然后呢 国王要去打架,但是只有当他的x%个及以上的直系下属(与他有直接关系的臣子)做好打架的准备了,他才能去打架 他的直系下属也有下属,也要其中x%及以上的下属做好打架准备了,那些直系下属才会开始准备

hdu 3641 数论 二分求符合条件的最小值数学杂题

http://acm.hdu.edu.cn/showproblem.php?pid=3641 学到: 1.二分求符合条件的最小值 /*==================================================== 二分查找符合条件的最小值 ======================================================*/ ll solve() { __int64 low = 0, high = INF, mid ; while(low <=

poj 杂题 - 2081 Recaman&#39;s Sequence

这道题目一开始就能知道考点在如何缩短查找时间.所以加快查找是我们的重点.但是在大数据面前,查找算法都不够快,所以我们用简单的hash思想来做. 我们开一个数组a,当出现了一个数b时,把该数作为下标调整值,即a[b] = -1,下一次出现该值的时候直接去找这个值作为下标的a值是否为-1即可. #include<stdio.h> #include<string.h> #define MAX 5000010 int p[MAX]={0}; int s[MAX]={0}; int main