题面
题目描述
A
l
e
x
Alex
Alex不喜欢无聊。
所以每当他感到无聊他就会想出一些游戏。一个冬天的晚上他想出了一个游戏并且决定开始玩这个游戏。
给定一个有
n
n
n个元素的序列
a
a
a。你可以做若干次操作。在一次操作中我们可以取出一个数
(
(
(假设他为
x
)
x)
x)并删除它,同时删除所有的序列中值为
x
+
1
x+1
x+1和
x
−
1
x-1
x−1的数。这一步操作会给玩家加上x分。
输入
第一行一个整数 n ( 1 ≤ n ≤ 1 0 5 ) n(1\le n\le10^5) n(1≤n≤105),说明这个序列有多少数。 第二行 n n n个整数,分别表示 a 1 a_1 a1, a 2 a_2 a2 … … …… …… a n a_n an ( 1 ≤ a i ≤ 1 0 5 ) . ( 1\le a_{i}\le 10^{5}). (1≤ai≤105).。
输出
一个整数,表示玩家最多能获得多少分
思路分析
根据题面可以看到删除所有的序列中值为
x
+
1
x+1
x+1和
x
−
1
x-1
x−1的数
也就是说数据的处理与输入的顺序无关
数据处理
for(int i=1;i<=N;i++){
scanf("%d",&x);
a[x]++;//运用桶的思想
Max=max(Max,x);//找到最大的数值
}//数据较小,可以不需要离散
经过处理后,可以直接查询、删除任意所以值为 k k k的数
D P DP DP式推导
这道题其实和这道题很像
Boredom | 大盗阿福 | |
---|---|---|
相同 | 取了 x x x后值为 x + 1 x+1 x+1和 x − 1 x-1 x−1的会被删除 | 相邻的店不能同时洗劫 |
不同 | 与序列无关,和每个数的值有关 | 与序列的顺序和值有关 |
他们的不同之处在数据处理
时已经处理好了
所以
D
P
DP
DP式也就可以随之推出:
f[i][0]=max(f[i-1][1],i>=2?f[i-2][1]:0);//当前数不取可以由上一个取或上上个取得来
f[i][1]=f[i-1][0]+a[i]*i;//当前数取便是由上个数不取加上当前数取的得分
完整代码
#include<bits/stdc++.h>
#define Maxn 100039
using namespace std;
int max(int a,int b){return a>b?a:b;}
int f[Maxn][2],N;
int a[Maxn],Max;
int main(){
scanf("%d",&N);
int x;
for(int i=1;i<=N;i++){
scanf("%d",&x);
a[x]++;
Max=max(Max,x);
}
for(int i=1;i<=Max;i++){
f[i][0]=max(f[i-1][1],i>=2?f[i-2][1]:0);
f[i][1]=f[i-1][0]+a[i]*i;
}
printf("%d",max(f[Max][1],f[Max][0]));
return 0;
}