算法_板子

用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]);
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值