#寒假集训[20200111-1]
scanf正则表达式
scanf("%s",%[0-9])//读入的为0-9的字符,读到非0-9时即停止
scanf("%s",&[^\r\n])//加^意味着不读后面的字符,所以为读入知道读到换行符
(常用函数:m=unique(a,a+n)-a;即去重,返回去重后最后一个元素位置;前提是数组有序;复杂度O(n))
JAVA在竞赛中主要应用于高精度&进制转换,因为有一个类型为BigInteger,但运行速度慢,时限为C的2-3倍
eg.
import java.io.*;
import java.util.*;
public calss Main
{
public static void main(String[] args)
{
Scanner cin=new Scanner(System.in);
while (cin.hasNext())
{
int a=cin.nextInt();
System.out.println(a);
}
}
}
hasNext()
nextInt()
next()
nextLine()
nextBigInteger()
System.out.print()
System.out.println()
DecimalFormat fd=new DecimalFormat(#.00#)
二分:
eg1.给出浮点数x,求sqrt(x)
#include<cstdio>
#include<algorithm>
#define eps 0.0000001
using namespace std;
double x,l,r,mid;
int main()
{
scanf("%lf",&x);
l=0,r=max(x,1.0);//因为若x小于1,就错误了……
while (r-l>eps)
{
mid=(l+r)/2;
if (mid*mid<=x) l=mid;
else r=mid;
}
printf("%lf\n",mid);
return 0;
}
eg2.查找一个有序数组中特定元素第一次出现和最后一次出现的位置
(二分查找略)
upper_bound(a,a+n,b)
lower_bound(a,a+n,b)
eg3.给定四个长度为n的数组,从每个数组中取一个值有多少种选择方案使四个值的和为0(n<4000)
题解:
因为\(n^2\)很小(并且主题为二分),所以考虑将前两个数组和后两个数组分别合并为一个\(n^2\)的数组,然后进行二分查找
注意:需要注意在找时要看内个元素出现了几次
另:将两个\(n^2\)的数组排序后可以不用二分查找,利用双指针O(\(n^2\))实现即可(首指针升序记录第一个数组找到哪,尾指针降序记录第二个数组找到哪)
eg4.给定一个二维数组A,相邻的两个元素保证右侧的大于左侧的,下侧的大于上侧的,查找x是否出现在此数组中(nm)
题解:
1、每一行或每一列(小的内个)均二分一次……复杂度O(min(n,m)log)
2、从矩阵的右上角开始找,向左即为减小,向下即为增大,即出现一条分界线,界线上为小于x的元素,界线下为大于x的元素,复杂度O(n+m)
eg4.给定一个数组A[1..n],找出一个位置使得其相邻位置的值都比当前位置小,假定A[0]=A[n+1]=-∞
题解:
将数组差分,因为我们可以证明两侧均为-∞时一定存在峰值,即两侧为-时中间一定有答案。所以每次选取中间的值,如果为-则在左半部分找,如果为+则在右边部分找
eg5.设将一个数组整体右移,后侧数据移到前侧,定义为数组的旋转。给定一个可能被旋转过的单调递增数组,求该数组的最小值
题解:
首先判断是否被旋转过:第一个值与最后一个值比较
每次取中间值,若小于第一个值则r=mid,否则l=mid
二分答案(最小值最大,最大值最小):
eg1.给出n个石头,给出到起点的距离。问去掉n个中的m个,使其间距的最小值最大
题解:
终极之河中跳石头,略。
eg2.有一些衣服,每件衣服有一定水量,有一个烘干机,每次可以烘一件衣服,每分钟可以烘干k件衣服。每件衣服如果不在烘干机里每分钟可以蒸发一滴水。问最少需要多少时间烘干所有衣服。
题解:
高中某一次模拟的T1,略。
eg3.给定n个物品,每个物品两个属性A与B。选取k个物品使得这些物品的A值之和除以B值之和最大。
题解:
01分数规划
1、二分答案,每次对于当前mid按A-mid*B降序排序,从大向小取k个,看和是否大于等于0。//sum(A)/sum(b)>=mid
复杂度O(nlognlogn)
2、
nth_element(a,a+n,k)//O(n)
//将数组中前k大的元素放在前k个位置,但不保证顺序
三分:
要求单峰。
注:单峰函数倒数单调,所以三分不方便时可求导后二分
mid=(l+r)/2;
midmid=(mid+r)/2;
黄金分割三分,经实践,跑得最快
midl=l+(r-l)*0.382;
midr=l+(r-l)*0.618;
eg1.给定一个开口向上的二次函数,设f(x)为这n个二次函数的最大值,求f(x)的极小值点
题解:
f(x)一定是一个单峰函数,所以三分后每次暴力取min即可
eg2.给定一个序列A,一个区间的poorness定义为这个区间内和的绝对值,weakness等于所有区间最大的poorness。求一个x使序列A全部减x后weakness最小。(n<=2e5)
题解:令f(x)=weakness,则f(x)为一个单峰函数(开口向上),三分求极值即可
eg3.给定x,求(\(x\)+\(x^2\)+\(x^3\)+...+\(x^y\))%p,(x,y<1e9,p>1e9)
题解:
1、利用等比数列求和及求逆元
2、若x为矩阵A呢?(不能用逆元)
利用ksm二分的思想,将其递归处理
eg.\(x+x^2+x^3+x^4\)
eg4.给定两个n位的大整数,求乘积,要求复杂度小于O(n^2)
题解:
折半,将两个大整数均分为前n/2位和后n/2位,变为4次(n/2)^2的乘法。
\(X=AB,Y=CD\)
\(X*Y=(A*2^{n/2}+B)(C*2^{n/2})=AC*2^{n}+(AD+BC)^{n/2}+BD*2^{n}\)
T(n)=4*T(n/2)+O(n);//Master定理求解复杂度问题,可知T(n)=O(\(n^2\))
所以还需要优化。
wqs二分
eg.给定n个物品,每个物品具有体积与价值,给定背包容量允许的情况下,选取不超过k个物品,可以收获的最大价值。(n<500,V<10000)
题解:
将每个物品的价值加x,背包容量加kx,每次做nv的背包可以知道选了多少个物品,随着x的增大,选的物品变少,最后得到答案。
eg2.一条直线上有n个村庄,给出每个村庄的坐标(整数)。要在这条直线上选k个地方建雕像,使得每个村庄到离其最近的雕像的距离的和最小,输出最小的和。(n<100000)
题解:
对每个雕像增加一个代价x,二分x来建雕像以控制建雕像的个数。