Gold3
Bessie 近一段迷上了一款游戏。这个游戏一开始会给你N个1到40的数字。她可以将两个相邻且相等的数字合并成一个比原来大1的数字(比如她可以将两个连续的7合并成一个8)游戏的最后得分是游戏结束时序列中最大的数字。请帮助Bessie算出她可以得到的最高分数。
输入:
第一行是一个整数N(N<=248),接下来N行每行一个数字,表示游戏开始时的序列
输出:
一个数字,表示Bessie的最大得分
样例输入:
4
1
1
1
2
样例输出:
3
数据规模:
2≦N≦248
================================================================
有 n 个 1 到 40 的数字,对于满足 ai=aj 且 I+1=j 的情况可以合并 ai 和 aj 变成他们原数+1.问最后序列中最大数字是多少.我们注意到 2<=n<=248, 果断暴力过!不过会有一点贪心的思想在里面.具体的是:每次在序列中找两个相邻且相同的数进行合并.但是通常情况下都会有很多对相邻且相同的数.应该选哪组进行合并呢?我的原则是:尽量先合并小的数,尽量先合并右边的数.例如:2 2 2 3 3,如果先合并 3 3 为 4,那么前面的三个 2 就失去了用武之地.而在三个 2 中,如果先合并前两个 2 为 3,那又造成了浪费.但是如果我们先合并右边两个 2 为 3,序列变成 2 3 3 3,进一步合并就是 2 3 4,这就是最优解.
但其实这题的正解是 dp,在 platinum1 中数据范围扩大到了 262144,模拟肯定超时.
考虑每个数字<=40,这题应该还有可以从数字本身入手的解法,不过我暂时还没想出来.
#include <algorithm>
#include <cstring>
#include <fstream>
#include <iostream>
using namespace std;
const int SIZE = 248+5;
ifstream fin("248.in");
ofstream fout("248.out");
int N, num[SIZE];
int main() {
ios::sync_with_stdio(false);
fin >> N;
for (int i = 0; i != N; ++i) {
fin >> num[i];
// fout << num[i] << " ";
}
while (1) {
// bool exist_same=false;
// for (int i = 1; i != N; ++i) {
// if (num[i] == num[i-1]) {
// exist_same = true;
// break;
// }
// }
// if (!exist_same) {
// break;
// }
int repeatNum=99, j;
for (int i = 1; i != N; ++i) {
if (num[i]==num[i-1] && num[i]<=repeatNum) {
repeatNum = num[i];
j = i;
}
}
if (repeatNum == 99) {
break;
}
++num[j-1];
// for (int i = 0; i != N; ++i) {
// fout << num[i] << " ";
// }
// fout << endl;
--N;
memmove(num+j, num+j+1, (N-j)*sizeof(int));
// for (int i = 0; i != N; ++i) {
// fout << num[i] << " ";
// }
// fout << endl << endl;
}
int ans=0;
for (int i = 0; i != N; ++i) {
ans = max(ans, num[i]);
}
fout << ans << endl;
return 0;
}