2022-02-21每日刷题打卡

2022-02-21每日刷题打卡

一本通——动态规划

1281:最长上升子序列

【题目描述】

一个数的序列bibi,当b1

你的任务,就是对于给定的序列,求出最长上升子序列的长度。

【输入】

输入的第一行是序列的长度N(1≤N≤1000)。第二行给出序列中的N个整数,这些整数的取值范围都在0到10000。

【输出】

最长上升子序列的长度。

【输入样例】

7 1 7 3 5 9 4 8
【输出样例】
4

准备一个动态规划数组dp,dp[i]的意思是,以第i个数为末尾的最长递增序列为dp[i]。遍历数组,每次遍历一个位置便从那个位置回头遍历一遍,如果回头遍历的数小于当前的数,就把那个数的dp+1赋给当前数的dp(此过程中要取最大值)。

最后遍历一遍dp数组,取最大值输出。

#include
using namespace std;
#include
#include
#include
#include
#include
#include
#include


int main()
{
	int n;
	cin >> n;
	vectorv(n);
	for (int i = 0; i < n; i++)cin >> v[i];
	vectordp(n,1);
	int res = 1;
	for (int i = 1; i < n; i++)
	{
		for (int j = i-1; j >= 0; j--)
		{
			if (v[i] > v[j])
			{
				dp[i] = max(dp[i], dp[j] + 1);
				res = max(res, dp[i]);
			}
		}
	}
	cout << res << endl;
	return 0;
}

【例9.11】01背包问题

【题目描述】

一个旅行者有一个最多能装 MM 公斤的背包,现在有 nn 件物品,它们的重量分别是W1,W2,…,WnW1,W2,…,Wn,它们的价值分别为C1,C2,…,CnC1,C2,…,Cn,求旅行者能获得最大总价值。

【输入】

第一行:两个整数,MM(背包容量,M<=200M<=200)和NN(物品数量,N<=30N<=30);

第2…N+12…N+1行:每行二个整数Wi,CiWi,Ci,表示每个物品的重量和价值。

【输出】

仅一行,一个数,表示最大总价值。

【输入样例】

10 4 2 1 3 3 4 5 7 9
【输出样例】
12
#include
using namespace std;
#include
#include
#include
#include
#include
#include
#include

typedef long long ll;
const int N = 210;
ll f[N], v[N], w[N];

int main()
{
	int n,m;
	cin >> n >> m;
	for (int i = 0; i < m; i++)
		cin >> v[i] >> w[i];
	for (int i = 0; i < m; i++)
	{
		for (int j = n; j >= v[i]; j--)
		{
			f[j] = max(f[j], f[j - v[i]] + w[i]);
		}
	}
	cout << f[n] << endl;
	
	return 0;
}

1259:【例9.3】求最长不下降序列

【题目描述】

设有由n(1≤n≤200)n(1≤n≤200)个不相同的整数组成的数列,记为:b(1)、b(2)、……、b(n)b(1)、b(2)、……、b(n)若存在i1

例如13,7,9,16,38,24,37,18,44,19,21,22,63,15。例中13,16,18,19,21,22,63就是一个长度为77的不下降序列,同时也有7 ,9,16,18,19,21,22,63组成的长度为88的不下降序列。

【输入】

第一行为nn,第二行为用空格隔开的nn个整数。

【输出】

第一行为输出最大个数maxmax(形式见样例);

第二行为maxmax个整数形成的不下降序列,答案可能不唯一,输出一种就可以了,本题进行特殊评测。

【输入样例】

14 
13 7 9 16 38 24 37 18 44 19 21 22 63 15
【输出样例】
max=8 
7 9 16 18 19 21 22 63

注意这个题,说的是不递减,不是递增,意思是等于和大于都可以,就是这里我被卡了一天,但题目明明说了数都各不相等,哪还有等于的说法嘛,出题不仔细啊,知道是这个地方出问题的时候我都要疯了(哭

就是普通的求个最长不递减序列的长度问题(做法同求最长递增序列),但是多了个输出序列的部分,对于这点有两个方法。

一:就先正常的求最长不递减序列的长度,然后记下最长序列的末尾数下标ans。然后根据这个下标为起点回头找,要找的是数小于当前元素,且长度比最长长度小1的元素,找到后更新一下记录的最长长度和元素,继续找下一个长度比记录长度小1且数小于我们记录的数的……以此类推,当找到最长长度为1时结束,把找到的序列输出。例:比如按照样例来说,最长长度是8,序列的末尾元素是63,下标是12,我们以12为起点去找长度为7的序列的末位数,且要小于63,即22,再去找长度为6……。

#include
using namespace std;
#include
#include
#include
#include
#include
#include
#include

const int N = 210;
int f[N],h[N];

void printf01(int num)
{
	cout << num << " ";
}

int main()
{
	int n;
	cin >> n;
	unordered_map>mymap;
	for (int i = 0; i < n; i++)
	{
		cin >> h[i];
	}
	f[0] = 1;
	int res = 1,ans=0;
	for (int i = 1; i < n; i++)
	{
		f[i] = 1;
		for (int j = i - 1; j >= 0; j--)
		{
			
			if (h[i] >= h[j])
			{
				f[i] = max(f[i], f[j] + 1);
				if (f[i] > res)
				{
					res = f[i];
					ans = i;
				}
			}
		}
	}
	
	cout << "max=" << res << endl;
	vectorv;
	int num = h[ans];
	v.push_back(num);
	for (int i = ans - 1; i >= 0; i--)
	{
		if (f[i] == res - 1 && h[i] <= num)
		{
			res--;
			num = h[i];
			v.push_back(num);
		}
	}
	reverse(v.begin(), v.end());
	for_each(v.begin(), v.end(), printf01);
	return 0;
}

第二个方法是用一个数组p,记录序列的上一个元素的下标,比如我们求样例的最长长度时,遍历到第3个元素9时,我们知道它可以接到第二个元素7上,所以数组里p[2]=1;如果当前遍历到的元素不能接到任何数上,那数组p就记录自身的下标,比如p[0]=0。这样依次类推,我们求完最长长度后,记录序列最后一个元素的下标,根据这个下标在p数组中取出序列的上一个下标……以此类推,当取出的下标为自身时,说明这是序列的最后一个数,结束程序。

#include
using namespace std;
#include
#include
#include
#include
#include
#include
#include

typedef long long ll;
const int N = 210;
ll f[N], h[N], p[N];

void printf01(ll num)
{
	cout << num << " ";
}

int main()
{
	int n;
	cin >> n;
	unordered_map>mymap;
	for (int i = 0; i < n; i++)
	{
		cin >> h[i];
		p[i] = i;
	}
	f[0] = 1;
	ll res = 1, ans = 0;
	//13 7 9 16 38 24 37 18 44 19 21 22 63 15
	for (int i = 1; i < n; i++)
	{
		f[i] = 1;
		for (int j = i - 1; j >= 0; j--)
		{

			if (h[i] >= h[j])
			{
				if (f[j] + 1 > f[i])
				{
					f[i] = f[j]+1;
					p[i] = j;
				}
				if (f[i] > res)
				{
					res = f[i];
					ans = i;
				}
			}
		}
	}

	cout << "max=" << res << endl;
	vectorv;
	bool flag = true;
	while (ans >= 0 && (p[ans] != ans) || (p[ans] == ans && flag))
	{
		if (p[ans] == ans)flag = false;
		v.push_back(h[ans]);
		ans = p[ans];
	}
	reverse(v.begin(), v.end());
	for_each(v.begin(), v.end(), printf01);
	return 0;
}

蓝桥杯——历届真题

历届真题 特别数的和【第十届】【省赛】【B组】

问题描述

小明对数位中含有 2、0、1、9 的数字很感兴趣(不包括前导 0),在 1 到
  40 中这样的数包括 1、2、9、10 至 32、39 和 40,共 28 个,他们的和是 574。请问,在 1 到 n 中,所有这样的数的和是多少?

输入格式

输入一行包含两个整数 n。

输出格式

输出一行,包含一个整数,表示满足条件的数的和。

样例输入

40

样例输出

574

评测用例规模与约定

对于 20% 的评测用例,1 ≤ n ≤ 10。 对于 50% 的评测用例,1 ≤ n ≤ 100。对于 80% 的评测用例,1 ≤ n ≤ 1000。对于所有评测用例,1 ≤ n ≤ 10000。

#include
using namespace std;




int main()
{
	int n,res=0;
	cin >> n;
	for (int j = 1; j <= n; j++)
	{
		int num = j;
		while (num)
		{
			int ans = num % 10;
			num /= 10;
			if (ans == 0 || ans == 1 || ans == 2 || ans == 9)
			{
				res += j;
				break;
			}
		}
	}
	cout << res << endl;
	return 0;
}

你可能感兴趣的:(笔记,动态规划,算法,c++)