usaco2016open gold3 248

21 篇文章 0 订阅
16 篇文章 0 订阅

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值