转载请注明出处:http://www.cnblogs.com/xianyue
题1:教师的困惑
题目描述
高考结束了,高三(一)班的王老师又即将要送走他的这一届的学生。为了给学生们留个念想,她决定去商店里为每一个学生买一个礼物。王老师班里一共有n个学生,商店里一共有m件礼物,每一件礼物都有各自的价格。王老师需要从这m件礼物里面购买n件,但是她买之前发现一个问题:如果给A同学买的礼物比B同学贵,B同学很可能就会觉得不公平。为了尽量避免这种情况的出现,王老师希望购买的n件礼物中最贵的哪一件的价格和最便宜的那一件的价格之差最小。请你帮王老师计算一下从m件礼物中购买n件使得最贵礼物和最便宜礼物地价格差最小对应地最小的价格差。
输入
第一行两个正整数n和m(2<=n<=m<=50)。
第二行m个正整数表示m件礼物的价格。
输出
输出从m件礼物中购买n件使得最贵礼物和最便宜礼物地价格差最小对应地最小的价格差。
样例输入
4 6
10 12 10 7 5 22
样例输出
5
题解
这道题我们需要先将m个数排序,然后从n-1到m-1遍历i,答案是a[i]-a[i-n+1]中地最小值。
代码
#include <iostream>
#include <algorithm>
using namespace std;
#define inf (1<<29)
int n, m, f = inf, a[55];
int main()
{
cin >> n >> m;
for (int i = 0; i < m; i ++)
cin >> a[i];
sort(a, a+m);
for (int i = n-1; i < m; i ++)
f = min(f, a[i]-a[i-n+1]);
cout << f << endl;
return 0;
}
题2:取数字1
题意
给你一个长度为n地数组a,你每次可以从其中取一个数a[k],当你取完a[k]之后,a[k-1]和a[k+1](如果有的话)便被锁定了(也就是说你取了a[k]之后便永远不能取a[k-1]和a[k+1]了),同时你将会获得a[k]地积分。求你最多能获得的积分。
输入
第一行一个数n。
接下来一行n个正整数表示数组a。
输出
你所能获得的最大的积分。
样例输入
5
5 3 5 3 4
样例输出
14
题解
这道题可以列状态转移方程:
f[i] = a[i] + max(f[i-2], f[i-3])
其中f[i]表示a[0]到a[i]这i+1个数并且我取了a[i]所获得的最大积分。
代码
#include <iostream>
using namespace std;
const int maxn = 100010;
int n, a[maxn], f[maxn], res = 0;
int main()
{
cin >> n;
for (int i = 0; i < n; i ++)
cin >> a[i];
f[0] = a[0];
f[1] = a[1];
f[2] = a[0] + a[2];
for (int i = 3; i < n; i ++)
{
f[i] = a[i] + max(f[i-2], f[i-3]);
}
for (int i = 0; i < n; i ++)
res = max(res , f[i]);
cout << res << endl;
return 0;
}
题3:取数字2
题意
给你一个长度为n地数组a,你每次可以从其中取一个数a[k],当你取完a[k]之后,数组中所有值为a[k]-1或a[k]+1的数都会被删除,同时你将会获得a[k]地积分。求你最多能获得的积分。
输入
第一行一个数n。(1<=n<=100000)
接下来一行n个正整数表示数组a。(1<=a[i]<=100000)
输出
你所能获得的最大的积分。
样例输入
5
5 3 5 3 4
样例输出
16
题解
可以列出状态转移方程:
f[i] = max(f[i-2], f[i-3]) + i * num[i];
其中,num[i]为a[i]==i的数的个数。
f[i]表示数值从0到i这个范围,且选择了所有数值为i的数,所能得到的总积分。
代码
#include <iostream>
#include <map>
using namespace std;
map<int, int> num;
const int maxn = 100010;
int n, a[maxn];
long long f[maxn];
int main()
{
cin >> n;
for (int i = 0; i < n; i ++)
{
cin >> a[i];
num[ a[i] ] ++;
}
f[0] = 0;
f[1] = 1 * num[1];
f[2] = 2 * num[2];
for (int i = 2; i <= 100000+3; i ++)
{
f[i] = max(f[i-2], f[i-3]) + (long long)i * (long long)num[i];
}
cout << f[100000+3] << endl;
return 0;
}
题4:减丝带
题目描述
小丽和小梅剪丝带。
已知四代的长度为n米,要求剪出来的四代的长度必须是a或b或c米。求:在满足条件的情况下它们最多能够剪出多少条四代。
输入
一行四个整数n,a,b,c。
输出
最多能够剪出的丝带的数目。
样例输入
7 5 5 2
样例输出
2
题解
这道题有点类似完全背包问题:
只不过背包被要求要正好装满。
所以一开始做了处理:除了f[0]以外的f[i]都置为一个无穷小的数。(关于f的计算见代码)
代码
#include <iostream>
using namespace std;
const int maxn = 4010;
#define inf (1<<29)
int n, a, f[maxn];
int main()
{
cin >> n;
for (int i = 1; i <= n; i ++)
f[i] = -inf;
for (int i = 0; i < 3; i ++)
{
cin >> a;
for (int j = a; j <= n; j ++)
f[j] = max(f[j], f[j-a]+1);
}
cout << f[n] << endl;
return 0;
}
题5:翻转游戏
题目大意
有一个长度为n的数组a,a[i]为0或者1。你可以选择两个整数i和j(0<=i<=j<n),然后对数组a的从a[i]到a[j]的数进行一次翻转操作(即a[i]到a[j]的每一个数x都会变为1-x),求进行了一次反转操作后,数组a中n个数的和最大为多少?
输入
第一行包括一个数n。
第二行n个数表示数组a。
输出
进行一次翻转操作后最大的可能总和。
样例输入
5
1 0 0 1 0
样例输出
4
题解
根据数组a我们可以求得一个数组b。
b[i]表示a[i]翻转后的获利。
- 如果a[i]一开始为0,则翻转后变为1,获利1
- 如果a[i]一开始为1,则翻转后变为0,获利-1
据此,我们可以对数组b求一个最大连续子序列和,将该最大连续子序列和加上数组a的元素总和便为答案。
代码
#include <iostream>
using namespace std;
const int maxn = 110;
int a[maxn], b[maxn], n, sum = 0, t;
int main()
{
cin >> n;
for (int i = 0; i < n; i ++)
{
cin >> a[i];
b[i] = (a[i] ? -1 : 1);
sum += a[i];
}
t = b[0];
int c = t;
for (int i = 1; i < n; i ++)
{
c = max(b[i], c + b[i]);
if (c > t)
t = c;
}
cout << sum + t << endl;
return 0;
}