用cin cout即使关闭同步可能也会tle,换成scanf
快读:
inline int read(){
int p=0,f=1; char c=getchar();
while (c<48||c>57) {if (c=='-') f=-1; c=getchar();}
while (c>=48&&c<=57) p=(p<<1)+(p<<3)+c-48,c=getchar();
return p*f;
}
climits中提供了int long ll ull类型最大最小值,cfloat定义float,double最大最小值
#include<climits>
#include<iostream>
using namespace std;
int main()
{
cout<<INT_MAX<<endl<<LLONG_MAX;
}
#include<cfloat>
#include<iostream>
using namespace std;
int main()
{
cout<<DBL_MAX<<endl<<DBL_MIN<<endl<<FLT_MAX<<endl;
}
灵活利用预处理:E1_f双陆棋
归并排序:逆序对个数、
#include<stdio.h>
int a[200000];
int temp[200000];
long long sum;
void merge_sort(int l, int r)
{
if(l == r) return;
int mid = (l + r) / 2;
int i, j, step;
merge_sort(l, mid);
merge_sort(mid + 1, r);
for(i = l; i <= r; i++)
{
temp[i] = a[i];
}
i = l, j = mid + 1;
for(step = l; step <= r; step++)
{
if(i > mid) a[step] = temp[j++];
else if(j > r) a[step] = temp[i++];
else if(temp[i] <= temp[j]) a[step] = temp[i++];
else if(temp[i] > temp[j])
{
sum += mid - i + 1;
a[step] = temp[j++];
}
}
return ;
}
int main()
{
int n, i;
scanf("%d", &n);
for(i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
}
merge_sort(1, n);
printf("%lld", sum);
}
二分查找:查找x第一个/最后一个位置
查找:对于一个升序序列,lower_bound返回序列中第一个大于等于x的数的地址,upper_bound返回序列中第一个大于x的数的地址。
具体实现如下,对于一个数组a,在[1,n]的区间内查找大于等于x的数y
int y = lower_bound(a + 1, a + 1 + n, x) - a;
//或者
int *p = lower_bound(a + 1, a + 1 + n, x);
int y = *p;
和sort类似,也可以添加比较函数
这样即使对于一个降序排列,我们也可以使用lower_bound返回第一个小于x的数的地址,可以写排序函数如下。
lower_bound(a + 1, a + 1 + n, x, cmp);
bool cmp(const int& a,const int& b){return a > b;}
也可以在调用的时候添加greater<int>(),是c++自带的大于函数。
lower_bound(a + 1, a + 1 + n, x, greater <int> () );
排序:利用c++sort,&结构体排序,
堆:小根堆为例,1 x把x插入堆,2 删除堆顶元素;3 打印堆顶元素
#include<stdio.h>
int arr[2000006];
int heapsize;
void swap(int, int);
void insert(int , int );
void del();
void heapify(int );
int main()
{
int n, way, x, a;
heapsize = 0;
scanf("%d", &n);
while(n--)
{
scanf("%d", &way);
if(way == 1)
{
scanf("%d", &a);
heapsize++;
arr[heapsize] = a;
insert(a, heapsize);
}
if(way == 2)
{
del();
}
if(way == 3)
{
printf("%d\n", arr[1]);
}
}
int i;
while(heapsize>0)
{
printf("%d ", arr[1]);
del();
}
}
void swap(int i, int j)
{
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
void insert(int a, int index)
{
if(index == 1) return;
else{
while(arr[index] < arr[index/2])
{
swap(index, index/2);
index = index / 2;
}
return ;
}
}
void del()
{
arr[1] = arr[heapsize];
heapsize--;
heapify(1);
}
void heapify(int index)
{
int l = index * 2;
int k;
while(l <= heapsize)
{
if((l+1 <= heapsize) && (arr[l+1] < arr[l])) k = l+1;
else k = l;
if(arr[index] < arr[k]) k = index;
if(k == index) break;
else
{
swap(k, index);
index = k;
l = index * 2;
}
}
return ;
}
c++实现的优先队列,小根堆(大小根堆可以通过相反数转换)
#include"iostream"
#include"algorithm"
#include"queue"
using namespace std;
priority_queue<int,vector<int>,greater<int> >q;
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
if(x==1) {scanf("%d",&x);q.push(x);}
else if(x==2) printf("%d\n",q.top());
else q.pop();
}
}
背包问题:
01背包:n个物体各有花费c价值w,花费v的最大价值
for (int i = 1; i <= n; i++)
for (int j = V; j >= 0; j--)
f[j] = max(f[j], f[j - c[i]] + w[i]);
完全背包:n种物体,每种无限个,各有花费c价值w,花费v的最大价值
for (int i = 1; i <= n; i++)
for (int j = c[i]; j <= V; j++)
f[j] = max(f[j], f[j - c[i]] + w[i]);
多重背包:n种物体,各有个数p花费c价值w,花费v的最大价值
for (int i = 1; i <= n; i++)
for (int j = V; j >= c[i]; j--)
for (int k = 1; k <= p[i] and k * c[i] <= j; k++)
f[j] = max(f[j], f[j - c[i] * k] + w[i] * k);
for (int i = 1; i <= n; i++) {
int num = min(p[i], V / c[i]); // V/c[i]是最多能放多少个进去,优化上界
for (int k = 1; num > 0; k <<= 1) { //这里的k就相当于上面例子中的1,2,4,6
if (k > num) k = num;
num -= k;
for (int j = V; j >= c[i] * k; j--) // 01背包
f[j] = max(f[j], f[j - c[i] * k] + w[i] * k);
}
}
上面是多重背包的二进制优化
混合背包:n种物体,有的一件有的无数件有的p件,各有花费c价值w,花费v的最大价值
只需在状态转移时将三种情况分类讨论即可
for (int i = 1; i <= n; i++) {
cin >> c >> w >> p;
if (p == 0) //完全背包
for (int j = c; j <= V; j++)
f[j] = max(f[j], f[j - c] + w);
else if (p == -1) //01背包
for (int j = V; j >= c; j--)
f[j] = max(f[j], f[j - c] + w);
else { //多重背包二进制优化
int num = min(p, V / c);
for (int k = 1; num > 0; k <<= 1) {
if (k > num) k = num;
num -= k;
for (int j = V; j >= c * k; j--)
f[j] = max(f[j], f[j - c * k] + w * k);
}
}
}
二维费用背包:在01背包的基础上,每个物品有两种花费c,g,最大分别为v,m,求最大花费
只需将状态增加一维即可,最后答案f[v][m];
for (int i = 1; i <= n; i++)
for (int j = V; j >= c[i]; j--)
for (int k = M; k >= g[i]; k--)
f[j][k] = max(f[j][k], f[j - c[i]][k - g[i]] + w[i]);