hiho 分冶专题
hiho的每周一题都不会很难,基本上就是一些很裸和经典的问题,这一次写了几道分冶专题的题,做个总结。
分冶最简单的就是二分,二分说简单,很简单,不过7,8行代码,不过也常常写挂,写成无限循环。
直接看题1128
http://hihocoder.com/problemset/problem/1128
很裸的直接二分查找,但是其中的第二种写法,事实上是很不实用的,未排序数组的二分查找,有一丝手写快排的味道,当然这道题直接可以在O(N)的复杂度便历得出结果。每次在2分过程中通过把比x小的数放x左边,把x大的数放x右边的方式,在边排序中边二分查找,效率不比直接排序二分高多少,但思想不错。
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
using namespace std;
#define ll long long
int n,k;
int a[1000005];
int p(int l,int r)
{
int k=a[r];
for(int i=l;i<r;i++)
{
if(a[i]<=a[r])
{
swap(a[i],a[l]);
l++;
}
}
swap(a[l],a[r]);
return l;
} int bs(int *a,int n,int k)
{
int l=0;
int r=n-1;
while(l<=r)
{
int mid=p(l,r);
if(a[mid]==k)
return mid;
else if(a[mid]<k)
l=mid+1;
else
r=mid-1;
}
return -1;
}
int main()
{
scanf("%d %d",&n,&k);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
int t=bs(a,n,k);
if(t==-1)
printf("%d\n",t);
else
printf("%d\n",t+1);
}
1133这道题http://hihocoder.com/problemset/problem/1133
找第k小的数
滚动数组,也算是手排加二分吧。
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
using namespace std;
#define ll long long
int n,k,c;
int a[2][1000005];
int p(int l,int r,int c)
{
int k=a[1-c][r];
int lf=l;
int rf=r;
for(int i=l;i<r;i++)
{
if(a[1-c][i]<k)
{
a[c][lf++]=a[1-c][i];
}
else if(a[1-c][i]>k)
{
a[c][rf--]=a[1-c][i];
}
a[c][lf]=k;
}
return lf;
} int bs(int n,int k)
{
int l=0;
int r=n-1;
c=1;
while(l<=r)
{
int mid=p(l,r,c);
if(l==r)
c=1-c;
if(mid==k)
return a[c][mid];
else if(mid<k)
l=mid+1;
else
r=mid-1;
c=1-c;
}
return -1;
} int main()
{
scanf("%d %d",&n,&k);
for(int i=0;i<n;i++)
{
scanf("%d",&a[0][i]);
}
int t=bs(n,k-1);
printf("%d\n",t);
}
1139http://hihocoder.com/problemset/problem/1139
二分判断,每次二分判断是否能符合题目的要求,这道题让我重新回忆了如何链式前向星建图,由于bfs O(N+E)的复杂度完全可以接受,就直接bfs搞起,写的很不熟练,也码了很长时间。
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
#define ll long long
int n,m,k,kk,u,v,w;
int head[10005];
int vis[10005];
int cnt=0;
struct edge
{
int v,w,next;
edge() {};
edge(int x,int y,int ww):v(x),w(y),next(ww){};
}e[200005]; struct node
{
int u,cc;
node() {};
node(int x,int y):u(x),cc(y){};
};
queue<node> q;
void add_edge(int u,int v,int w)
{
e[cnt]=edge(v,w,head[u]);
head[u]=cnt++;
} bool bfs(int key)
{
// printf("cas %d\n",key);
memset(vis,0,sizeof(vis));
while(!q.empty())
q.pop();
q.push(node(1,0));
vis[1]=1;
while(!q.empty())
{
node t=q.front();
q.pop();
for(int xx=head[t.u];xx!=-1;xx=e[xx].next)
{
int v=e[xx].v;
if(e[xx].w<=key&&t.cc+1<=k)
{
if(v==kk)
return 1;
if(vis[v])
continue;
q.push(node(v,t.cc+1));
vis[v]=1;
}
}
}
return 0;
} int main()
{
// freopen("input.txt","r",stdin);
memset(head,-1,sizeof(head));
scanf("%d%d%d%d",&n,&m,&k,&kk);
int mm=-1;
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&u,&v,&w);
add_edge(u,v,w);
add_edge(v,u,w);
mm=max(w,mm);
}
if(n==1)
{
printf("0\n");
return 0;
}
int l=0,r=mm;
while(l<r)
{
int mid=(r+l)/2;
if(bfs(mid))
{
r=mid;
}
else
l=mid+1;
}
printf("%d\n",l);
}
1141http://hihocoder.com/problemset/problem/1141
逆序对,老问题,常用方法就归并排序和树状数组,这两个方法都写一次。
并归排序就是先通过递归二分,再合并,类似后序便历,然后在合并的过程中求出逆序对的个数。
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
#define ll long long
int n;
int a[100005];
int temp[100005];
ll res=0;
void pp(int l,int mid,int r)
{
int lf=l,rf=mid,ls=mid+1,rs=r;
int ans=0;
while(lf<=rf&&ls<=rs)
{
if(a[lf]<=a[ls])
{
temp[ans++]=a[lf++];
res+=(ls-mid-1);
}
else
{
temp[ans++]=a[ls++];
}
}
while(lf<=rf)
{
temp[ans++]=a[lf++];
res+=(ls-mid-1);
}
while(ls<=rs)
{
temp[ans++]=a[ls++];
}
for(int i=0;i<ans;i++)
a[l+i]=temp[i];
} void merge_sort(int l,int r)
{
if(l<r)
{
int mid=(l+r)/2;
merge_sort(l,mid);
merge_sort(mid+1,r);
pp(l,mid,r);
}
} int main()
{
//freopen("input.txt","r",stdin);
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
merge_sort(0,n-1);
cout<<res<<endl;
}
树状数组:
树状数组就是这样的一种数据结构,原理类似多重背包的二进制做法,都把O(N)的复杂度简化到log的复杂度。
目前只会单点修改,查询区间。
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
#include<queue>
#include<set>
using namespace std;
#define ll long long
int n; struct node
{
int pos,val,cc;
}a[100005];
int r[100005];
int c[100005];
bool cmp(node a,node b)
{
return a.val<b.val;
} int lowbit(int x)
{
return x&(-x);
} void add(int i,int v)
{
while(i<=n)
{
c[i]+=v;
i+=lowbit(i);
}
} ll getsum(int x)
{
ll sum=0;
while(x)
{
sum+=c[x];
x-=lowbit(x);
}
return sum;
}
int main()
{
//freopen("a+b.in","r",stdin);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i].val);
a[i].pos=i;
}
sort(a+1,a+n+1,cmp);
r[a[1].pos]=1;
for(int i=2;i<=n;i++)
{
if(a[i].val==a[i-1].val)
r[a[i].pos]=r[a[i-1].pos];
else
r[a[i].pos]=r[a[i-1].pos]+1;
}
ll ans=0;
for(int i=1;i<=n;i++)
{
add(r[i],1);
ans+=i-getsum(r[i]);
}
cout<<ans<<endl;
}
注意离散化的时候同样大的数值一样。
1142 三分
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
#define ll long long
int a,b,c,x,y;
const double eps=1e-8;
double dis(double xx)
{
double yy=(a*xx*xx+b*xx+c);
return sqrt((x-xx)*(x-xx)+(y-yy)*(y-yy));
} int main()
{
//freopen("input.txt","r",stdin);
scanf("%d%d%d%d%d",&a,&b,&c,&x,&y);
double lf=-200,rf=200,midf,midr;
while(rf-lf>eps){
midf=(lf*2+rf)/3;
midr=(lf+rf*2)/3;
if(dis(midf)<dis(midr))
rf=midr;
else
lf=midf;
}
printf("%.3f\n",dis(lf));
}
简单的说啊,首尾a,b;取两个三分点,然后如果求最小值,答案肯定包括小的那一段,求最大值,包括大的那一段。
hiho 分冶专题的更多相关文章
- Leetcode之分治法专题-169. 求众数(Majority Element)
Leetcode之分治法专题-169. 求众数(Majority Element) 给定一个大小为 n 的数组,找到其中的众数.众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素. 你可以假设数组是 ...
- Leetcode之分治法专题-654. 最大二叉树(Maximum Binary Tree)
Leetcode之分治法专题-654. 最大二叉树(Maximum Binary Tree) 给定一个不含重复元素的整数数组.一个以此数组构建的最大二叉树定义如下: 二叉树的根是数组中的最大元素. 左 ...
- hiho拓扑排序专题 ——第四十八、四十七周
拓扑排序·一 分析: 此题就是求一个有向图中是否存在环. 如存在环则输出"Wrong", 若不存在环, 说明课程安排的合理,输出"Correct". 题中的提示 ...
- Leetcode Kth Smallest Element in a BST
Given a binary search tree, write a function kthSmallest to find the kth smallest element in it. Not ...
- 逆序数 POJ 2299 Ultra-QuickSort
题目传送门 /* 题意:就是要求冒泡排序的交换次数. 逆序数:在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序. 一个排列中逆序的总数就称为这个排列的逆 ...
- 【NOI2005】维护数列
https://daniu.luogu.org/problem/show?pid=2042 一道伸展树维护数列的很悲伤的题目,共要维护两个标记和两个数列信息,为了维护MAX-SUM还要维护从左端开始的 ...
- vuex的使用及持久化state的方式
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化. 当我们接触vuex的时候,这是我们最先看到 ...
- LeetCode 4. Median of Two Sorted Arrays & 归并排序
Median of Two Sorted Arrays 搜索时间复杂度的时候,看到归并排序比较适合这个题目.中位数直接取即可,所以重点是排序. 再来看看治阶段,我们需要将两个已经有序的子序列合并成一个 ...
- vuex的使用及持久化state的方式详解
vuex的使用及持久化state的方式详解 转载 更新时间:2018年01月23日 09:09:37 作者:baby格鲁特 我要评论 这篇文章主要介绍了vuex的使用及持久化state的方 ...
随机推荐
- java加载资源文件
className.class.getResourceAsStream 用法: 第一: 要加载的文件和.class文件在同一目录下,例如:com.x.y 下有类Test.class ,同时有资源文件c ...
- web验证码
前台引用.aspx: <%@ Page Language="C#" AutoEventWireup="true" CodeFile="YanZh ...
- (原)ubuntu上安装dlib
转载请注明出处: http://www.cnblogs.com/darkknightzh/p/5652791.html 参考网址: http://stackoverflow.com/questions ...
- [Head First Python]6. 定制数据对象:打包代码与数据
相同功能,演进实现 数据文件 sarah2.txt sarah Sweeney,2002-6-17,2:58,2.58,2:39,2-25,2-55,2:54,2.18,2:55,2:55 1- 返回 ...
- 一些常用Linux命令简记
1.重命名文件夹 mv xxx/ yyy/ 将xxx文件夹重命名为yyy(前提是当前目录没有yyy文件夹,否则就移进去了!) 2.数据盘重新挂载 一.# umount /mnt(卸载硬盘已挂载的mn ...
- javaweb jsp页面上传excel文件
servlet: private static final long FILE_MAX_SIZE = 4 * 1024 * 1024; if (!ServletFileUpload.isMultipa ...
- BZOJ 1065 奥运物流
http://www.lydsy.com/JudgeOnline/problem.php?id=1065 思路:由于n个点,有n条边,因此由根就会引出一个环,我们枚举环的长度,在那个长度断开,我们假设 ...
- C# 语法技巧_三目运算_switch_case
一.三目运算符 三目运算符的一种简便写法: bool b = str == "abc" ? false : true; 当是自身时,实际上别吝啬那一个括号,有一个括号,实际上更容易 ...
- linux vi 中s 替换方法
vi/vim 中可以使用 :s 命令来替换字符:s/vivian/sky/ 替换当前行第一个 vivian 为 sky :s/vivian/sky/g 替换当前行所有 vivian 为 sky :n, ...
- UNIX网络编程---TCP客户/服务器程序示例(五)
一.概述 客户从标准输入读入一行文本,并写给服务器 服务器从网络输入读入这行文本,并回射给客户 客户从网络输入读入这行回射文本,并显示在标准输出上 二.TCP回射服务器程序:main函数 这里给了函数 ...