补题日记(3)

1、洛谷 台阶问题

传送门:台阶问题

最基础的台阶问题是一次可以走一层或者两层台阶 , 而这题不同的是一次可以走1到n层台阶。

那么该怎么做呢,首先我们还是从基础台阶问题来分析在基础台阶中我们假设一个dp数组dp[i] 是走到第i个台阶有几种走法那么他的走法是dp[i-1] + dp[i-2[所以就是dp[i] = dp[i-1] + dp[i-2];

因为有两种方案数。如果有三种呢,就是dp[i-1] +dp[i-2] + dp[i-3],k种的话就是dp[i-1] + ...+dp[i-k](i -k > 0)所以我们的状态转移方程就得到了。

下面是ac代码:

#include <bits/stdc++.h>
#define mod 100003
using namespace std;
using ll =long long;
const int N =1e6;

ll dp[N];
int n,k;

int main(){
	cin>>n>>k;
	dp[0] = 1;
    dp[1] = 1;
	for(int i =2;i<=n;++i){
		for(int j =max(0,i-k);j<=i-1;++j){
			dp[i] = (dp[i] +dp[j] )%mod;
		}
	}
	cout<<dp[n];
	
	
	return 0;
}

2、洛谷 数列分段

传送门:https://www.luogu.com.cn/problem/P1181

这题也是非常简单了,我们之前用一个sum就行了

#include <bits/stdc++.h>
using namespace  std;
const int N  =100009;
int a[N];
int n,m;
int main(){
	cin>>n>>m;
	for(int i =1;i<=n;++i)cin>>a[i];
	int sum =0;
	int ans =1;
	for(int i =1;i<=n;++i){
		if(sum +a[i]<= m)sum +=a[i];
		else sum= a[i] , ans++;
	}
	cout<<ans;
	return 0;
}

3、牛客 数组段数

传送门:点这里

本道题唯一的难点就是范围 ,范围比较大要用前缀和数组来优化

for(int i =1;i<=n;++i){
        cin>>a[i];
        b[i] = b[i-1] + (a[i] != a[i-1]);
    }

这段代码就是优化,什么意思呢? 如果这个数和前面的数不一样的话,隔板就加一个,比如

1 2 2 3 , 这里1和前面那个数字(但其实前面没有数字,但是数组b[1]的前面是b[0])就有一个隔板 , 然后1和2之间也有一个隔板 , 2和3 之间又有一个隔板。所以有三个隔板,那么隔板的位置在哪里呢?这是我们需要考虑的,如果我们把1 2 2 3编号成 1 2 3 4 ,四个数字那么位置其实在第 1号 ,第2号 ,第四号 。然后就是如果两个数之间没有隔板的话, 本来就是有一段的,所以最后答案是要加1的。那么如果说询问区间 2 和  4 ,我们知道应该是有两个隔板的,如果按照正常的前缀和的话就是 b[4] - b[2-1] = 3 - 1=2,2+1 = 3了,与答案不符合 , 所以不能包括 上区间的左端点 ,应该是b[4] - b[2];

一下就是ac代码

#include<bits/stdc++.h>
using namespace std;

const int N = 2e5 + 10;
int a[N], b[N];

int main()
{
    int n,m;
    cin>>n>>m;
    for(int i =1;i<=n;++i){
        cin>>a[i];
        b[i] = b[i-1] + (a[i] != a[i-1]);
    }
    while(m--){
        int l,r;
        cin>>l>>r;
        cout<<b[r] - b[l] +1<<'\n';
    }

    return 0;
}

4、一系列背包问题的总结与模板

 一、01背包

这个就是非常经典的问题了,昨天的文章中还写了变形的01背包问题,那么我们还是来介绍一下01背包这个问题吧。

一个包的体积为V , 有n个物品 每个物品的价值为wi , 体积为vi,而且每个物品只能使用一次,问能装价值最多是多少? 我们采用优化的 一维数组来解决这个问题

for(int i =1;i<=n;++i)  //遍历物品
    for(int j =v;j>=v[i];--j)  //倒着遍历背包
        dp[j] = max(dp[j] , dp[j - v[i]] + w[i] )  
 //v[i]表示单个物品的体积  w[i]表示单个物品的价值

那么这种最基础的01背包也是非常简单的,一定要掌握

二、完全背包

完全背包和01背包唯一的不同点就是每个物品能无限次的选取,此时我们只需要正的遍历背包即可

for(int i =1;i<=n;++i)
    for(int j =v[i];j<=V;++j)
        dp[j] = max(dp[j] , dp[j - v[i]] +w[i]);

三、多重背包

这个就是每个物品可以选择s次,但是这样的话时间复杂度会很高。我们可以采用优先队列或者二进制优化,这里主要说一下二进制优化的办法。

我们可以把s分成1,2,4,....,x几部分 ,比如8是1,2,4,1.分成这几个部分。

for(int i =1;i<=n;++i)
 int v,w,s;
for(int  k = 1;k<=s;s -= k,k +=k){
    for(int j =m;j>=k*v;--j)dp[j] = max(dp[j]  ,dp[j -v*k]+w*k);
}
for(int  j =m;j>=s*v;--j)dp[j] = max(dp[j]  ,dp[j -v*s]+w*s);

四、二维费用背包

这类问题是既有体积,又有重量,多了一个参数,但是大体不变

for(int i =1;i<=n;++i){
	int v,m,w;cin>>v>>m>>w;
	for(int j = M;j>=m;--j){
		for(int k =V;k>=v;--k){
			dp[j][k] = max(dp[j][k] , dp[j-m][k-v] + w);
		}
	}
}

五、分组背包

这个问题呢就是物品分成了几组比如

a b b c

a c d 

c d

这些物品被分成了三组,每组只能选一个物品,或者可以不选

for(int i =1;i<=n;++i){
	for(int j=1;j<=V;++j)dp[i][j] = dp[i-1][j];
	int s;cin>>s;
	while(s--){
		int v,w;cin>>v>>w;
		for(int k =V;k>=v;--k){
			dp[i][k] = max(dp[i][k] , dp[i-1][k-v]+w)
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值