10月22日NOIP2018提高组省一冲奖班模测训练2
T3 XYK的音游
题目描述
XYK最近入坑了一个新音游。
游戏界面上有Ñ个并排的按键,当前这首歌有米个鼓点。游戏的玩法是在鼓点的时刻移动鼠标到对应的按键上并点击来获取分数。
对于第我个鼓点,我们用TI,WI,XI来描述,表示在时间点击第XI个按键会获得无线的分数。
由于xyk手速很慢,每个时刻只能移动p个按键的距离。也就是说如果s时刻xyk的鼠标在第pos个按键上,那么s + 1时刻他能够把鼠标移动到[pos-p ,pos + p]的按键。
在0时刻xyk可以把鼠标放在任意位置。鼓点出现的时刻大于0.保证同一时间不会有两个鼓点。由于这款音游并不看重连击,xyk希望分数尽可能高就好。请你帮助他计算他能获得的最高分数。
输入格式
第一行三个正整数 n,m,p。
接下来 m 行每行三个正整数 t_i,w_i,x_i 描述第 i 个鼓点。
输出格式
一行一个整数表示最大分数。
输入样例
5 5 1
2 42 4
3 23 4
1 70 4
2 31 5
1 85 5
输出样例
150
数据范围
对于30%的数据,p = 1.
对于50%的数据,n×m≤106.
对于100%的数据,n,m≤100000,p≤5,ti≤1000000。
思路
DP + BIT
1)部分分,只用DP
先按照时间排序,再用DP
状态设计: dp [i]表示第i个鼓点一定选的得分
状态转移: dp [i] = max(dp [j])+ s [i],这里的s [i]是点击第i个鼓点所得的分数,(自己的变量比较好记)(〜¯▽¯ )〜,并且要满足以下要求
解释:十分显然,既然一定要点击第i个鼓点,那么手残的xyk要有时间从j鼓点移动到我鼓点才可以
复杂度:
2)100分DP + BIT
的复杂度只能拿部分分,所以我们可以用一个树状数组来维护
类似于用BIT求LIS的思路,令,那么之前状态转移的条件就变成了,稍微移一下项就变成了
所以按照可以排序,再使用树状数组维护
代码(40分)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
const int MAXN = 1e5 + 5;
struct drumbeat{
int t;
int x;
int s;
}a[MAXN];
int n, m, p;
int dp[MAXN];
int maxj, maxi;
inline int read ()
{
char ch = getchar ();
while (!isdigit (ch)) ch = getchar ();
int x = 0;
while (isdigit (ch)) x = x * 10 + ch - '0', ch = getchar ();
return x;
}
bool cmpt (const drumbeat &a, const drumbeat &b)
{
return a.t < b.t;
}
int main ()
{
n = read (), m = read (), p = read ();
for (int i = 1; i <= m; i ++){
a[i].t = read (), a[i].s = read (), a[i].x = read ();
}
sort (a + 1, a + 1 + m, cmpt);
maxi = 0;
for (int i = 1; i <= m ; i ++){
maxj = 0;
for (int j = 1; j <= i; j ++){
if (p * (a[i].t - a[j].t) >= fabs (a[i].x - a[j].x))
maxj = max (maxj, dp[j]);
}
dp[i] = maxj + a[i].s;
maxi = max (maxi, dp[i]);
}
printf ("%d", maxi);
return 0;
}
比赛时写了40分之后过了几天,代码风格竟然完全不一样了¯▽¯
代码(AC)
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 1e5 + 5;
const int INF = 0x3fffffff;
#define lowbit(x) ((x)& (-x))
int n, m, p, l, ans;
int dp[MAXN], T[MAXN], D[MAXN];
struct Node{
int t, s, x, k;
bool operator < (const Node &rhs) const
{
if (p * t - x == p * rhs.t - rhs.x) return p * t + x < p * rhs.t + rhs.x;
else return p * t - x < p * rhs.t - rhs.x;
}
}a[MAXN];
inline int read ();
inline int queryMax (int x);
inline void motify (int x, int y);
int main ()
{
n = read (), m = read (), p = read ();
for (int i = 1; i <= m; ++ i){
a[i].t = read (), a[i].s = read (), a[i].x = read ();
a[i].k = p * a[i].t + a[i].x;
}
sort (a + 1, a + 1 + m);
for (int i = 1; i <= m; ++ i){
D[i] = a[i].k;
}
sort (D + 1, D + 1 + m);
l = unique (D + 1, D + 1 + m) - D;
for (int i = 1; i <= m; ++ i){
a[i].k = lower_bound (D + 1, D + 1 + l, a[i].k) - D + 1; //离散化
}
for (int i = 1; i <= m; ++ i){
dp[i] = queryMax (a[i].k) + a[i].s;
ans = max (ans, dp[i]);
motify (a[i].k, dp[i]);
}
printf ("%d", ans);
return 0;
}
inline int read ()
{
char ch = getchar ();
while (!isdigit (ch)) ch = getchar ();
int x = 0;
while (isdigit (ch)){
x = x * 10 + ch - '0';
ch = getchar ();
}
return x;
}
inline int queryMax (int x)
{
int res=-INF;
while (x){
res = max (res, T[x]);
x -= lowbit (x);
}
return res;
}
inline void motify (int x ,int y)
{
while (x <= l){
T[x] = max (T[x], y);
x += lowbit (x);
}
return ;
}
感谢你看到了最后,如果有错的地方也请多多指教,
说到音游,是在是忍不住要推荐几个炒鸡好玩手机音游:
兰空VOEZ,Deemo,Arcaea,Cytus,osu,虽然osu还没玩过,但是很多人向我推荐的说,还有其实好想玩Diva,但是没有设备,希望出手游啊啊啊ε=ε= ε=(#>д<)ノ,不过还是为公主殿下疯狂打电话,吐槽初音速,对这个有一点失望,顺带一提,本人LL的信徒一枚,所以一定要说一下LL了,最喜欢真姬了(/ω\),还有niko,小鸟和海爷,博爱的我,明明是因为她们都太可爱了,不过除去信仰加成之外,其实并不太喜欢LL的模式,但是它的按键操作还是很新颖的