五一清北总结——day1+day2
Posted wxyww
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了五一清北总结——day1+day2相关的知识,希望对你有一定的参考价值。
五一清北学习总结
——day1+day2
一、排序
1.快速排序
O(nlogn)的排序,用sort可以快速完成,但是可以被卡,手写sort利用随机数可以避免被卡掉。
代码:
void quick_sort(int *a, int l, int r)
{
swap(a[l], a[rand()*rand() % (r -l + 1) +l]);
int tmp = a[l];
int l_ = l, r_ = r;
while (l < r)
{
while (l < r)
{
if (a[r] > tmp) r--; //a[r]落在正确的位置
else
{
a[l] = a[r];
l++;
break;
}
}
while (l < r)
{
if (a[l] < tmp) l++; //a[l]落在正确的位置
else
{
a[r] = a[l];
r--;
break;
}
}
}
a[l] = tmp;
if (l - l_ > 1) quick_sort(a, l_, l - 1);
if (r_ - r > 1) quick_sort(a, r + 1, r_);
}
2.冒泡排序
每次选出一个最大值或最小值放在正确的位置,进行n-1次循环,然后就得到了一个有序序列。复杂度O(n2),一般不使用。
代码:
void bubble_sort(int *a, int l, int r, int n)
{
for (int i = 1; i < n; i++)
{
for (int j = l; j < r; j++)
{
if (a[j] > a[j + 1]) swap(a[j], a[j + 1]);
}
}
}
3.归并排序
采用分治的方法,达到O(nlogn)排序的方法,采用递归实现,可以用来找逆序对。
代码:
void merge_sort(int *a, int l, int r)
{
if (l == r) return;
int mid = (l + r) >> 1;
merge_sort(a, l, mid);
merge_sort(a, mid + 1, r);
int i = l, j = mid + 1;
//b:辅助数组
for (int k = l; k <= r; k++)
{
if (j > r || (i <= mid && a[i] < a[j]))
{
b[k] = a[i];
i++;
ans += j - (mid + 1);
}
else
{
b[k] = a[j];
j++;
}
}
for (int k = l; k <= r; k++)
a[k] =b[k];
}
4.插入排序
在线排序算法,每插入一个元素将其与前一个元素比较,如果位置不对,就将其交换,知道到达正确位置。
5.堆排序
利用二叉树实现的一种排序,可以用stl里的优先队列实现。
二、快速幂
采用二分的思想,将一个求幂的式子的幂进行不断除以二,然后降低复杂度,快速幂的思想可以运用于所有a*b的运算,其中*代表任意一种运算符。例如快速乘法,快速乘法并不比普通的乘法快,但是它可以完成较大数相乘,对一个数取模的情况,因为他可以一边乘一边模。
代码:
lude<cstdio>
#include<iostream>
using namespace std;
int fpow(int a,int x)
{
int ans=1;
for(int now=a;x;x>>=1,now=now*now)
{
if(x&1) ans=ans*now;
}
return ans;
}
int cf(int a,int x,int mo)
{
int ans=o;
for(int now=a;x;x>>=1,now=(now+now)%mo)
if(x&1) ans=(ans+now)%mo;
return ans;
}
int main()
{
int a,x,mo;
scanf("%d%d",&a,&x);
printf("%d",fpow(a,x));
printf("%d",cf(a,x,mo));
return 0;
}
三、高精
用于大整数运算,将其包装在结构体里方便使用。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<string>
using namespace std;
struct bignum
{
int n;
int a[500];
bignum()
{
n = 0;
memset(a, 0, sizeof(a));
}
bignum(string s)
{
n = s.size();
memset(a, 0, sizeof(a));
for (int i = 0; i < n; i++)
a[i] = s[n - 1 -i] -‘0‘;
}
bignum(int s)
{
memset(a, 0, sizeof(a));
n = 0;
while (s > 0)
{
a[n] = s % 10;
s /= 10;
n++;
}
}
void work()
{
for (int i = 0; i < n; i++)
{
if (a[i] < 0)
{
int tmp = (-a[i] - 1) / 10 + 1;
a[i] += 10 * tmp;
a[i + 1] -= tmp;
}
if (a[i] >= 10)
{
int tmp = a[i] / 10;
a[i] -= 10* tmp;
a[i + 1] += tmp;
if (i == n - 1 && a[i + 1] > 0) n++;
}
}
while (n > 0 && a[n - 1] == 0) n--;
}
void print()
{
for (int i = n - 1; i >= 0; i--)
cout << a[i];
cout << endl;
}
};
bignum operator + (const bignum &a, const bignum &b)
{
bignum c;
c.n = max(a.n, b.n);
for (int i = 0; i < c.n; i++)
c.a[i] = a.a[i] + b.a[i];
c.work();
return c;
}
bignum operator - (const bignum &a, const bignum &b)
{
bignum c;
c.n = max(a.n, b.n);
for (int i = 0; i < c.n; i++)
c.a[i] = a.a[i] - b.a[i];
c.work();
return c;
}
bignum operator * (const bignum &a, const bignum &b)
{
bignum c;
c.n = a.n + b.n - 1;
for (int i = 0; i < a.n; i++)
for (int j = 0; j < b.n; j++)
c.a[i + j] += a.a[i] * b.a[j];
c.work();
return c;
}
int main()
{
string s;
cin >> s;
int x;
cin >> x;
bignum a(s);
bignum b(x);
(a + b).print();
(a - b).print();
(a * b).print();
return 0;
}
四、二分
可以降低复杂度,需要找到单调性,然后根据单调性对要二分的数进行二分,然后将二分到的数进行check,知道找到正确答案或者达到一定精度。
采用二分的题目中常常蕴含着最大值最小或者最小值最大的信息。
如果想不清楚在循环里是应该取l=mid+1还是r=mid-1那么就可以再循环外面在进行一次check。
五、前缀和数组与差分数组
前缀和数组用来记录前i个数字之和,差分数组则是储存当前数与前一个元素之差。
对于前缀和数组与差分数组有:前缀和数组的差分数组是原数组,差分数组的前缀和数组是原数组。
对于差分数组有:当一个区间同时加或减同一个数时,对于该序列的差分数组,只需将区间首元素位置加或减这个数,区间尾元素的下一个位置进行相反处理。
利用这两个性质,可以完成树状数组的区间修改与单点查询。
以上是关于五一清北总结——day1+day2的主要内容,如果未能解决你的问题,请参考以下文章
2016.10.29 清北学堂NOIP冲刺班Day1 AM 考试总结