并没有传送门
题目描述
E.Space 喜欢打音游。
但是他技术不好,总是拿不到全连(Full Combo)。
现在他面前有一份乐谱,乐谱的其中一段有 n n n 个连续的单键音符。
相邻两个音符的到来时间均相等,我们可以认为第 i i i 个音符会在第 i i i 个时刻到来。
点击一个音符,E.Space 需要一段准备时间来进行移动手指之类的操作。由于音符的位置和周围情况不同,点击每
个音符的准备时间也不同。
在一个音符的准备时间内,E.Space 没法做到去点击其它音符,但是不同音符的准备时间范围可以互相重叠。形式化地,令第 i i i 个音符的准备时间为 t i t_i ti 个单位时间,那么如果E.Space 选择去点击第 i i i 个音符,那么他就没法点击所有到来时刻在 ( i − t i ; i + t i ) (i - t_i; i + t_i) (i−ti;i+ti)中的音符。
为了获得更高的分数,E.Space 还计算了每个音符的性价比。一个音符的性价比等于点击这个音符得到的分数除以
E.Space 点击它所需要的准备时间。
E.Space 就不指望全连了,他只是想让你帮他计算一下他最多可以得到多少分数。
输入输出格式
输入格式
从文件fc.in 中读入数据。
第一行一个正整数 n n n 。
第二行 n n n 个正整数,第 i i i 个正整数表示 t i t_i ti 。
第三行 n n n 个正整数,第 i i i 个正整数表示第 i i i 个音符的性价比 a i a_i ai。
输出格式
输出到文件fc.out 中。
一行一个正整数,表示E.Space 可能达到的最高分数。
输入输出样例
输入样例#1:
5
2 3 2 1 2
3 1 2 9 4
输出样例#1:
18
样例解释
E.Space 可以选择点击第 1 , 3 , 5 1, 3, 5 1,3,5 个音符,分数为$2 * 3 + 2 * 2 + 2 * 4 = 18 $。
解题分析
设
d
p
[
i
]
dp[i]
dp[i]为必选第
i
i
i个音符最大的收益, 那么就有:
d
p
[
i
]
=
m
a
x
j
∈
[
1
,
i
−
1
]
,
m
a
x
(
t
i
,
t
j
)
≤
i
−
j
(
d
p
[
j
]
)
+
v
a
l
[
i
]
dp[i]=max_{j\in [1,i-1],max(t_i,t_j)\le i-j}(dp[j])+val[i]
dp[i]=maxj∈[1,i−1],max(ti,tj)≤i−j(dp[j])+val[i]
如果我们把一个
d
p
[
i
]
dp[i]
dp[i]看做三元组
(
i
,
i
+
t
i
,
d
p
[
i
]
)
(i,i+t_i,dp[i])
(i,i+ti,dp[i])的话, 这个问题就变成了一个二维偏序问题, 可以花式
n
l
o
g
2
(
n
)
nlog^2(n)
nlog2(n)解决。
但是这样是要 T T T的, 仔细观察发现三元组的 i + t i i+t_i i+ti这一维每次查询时递增的, 那么直接用 v e c t o r vector vector储存暂时不满足第二维要求的值, 另一维树状数组维护前缀最小值就好。
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <vector>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define lbt(i) ((i) & (-(i)))
#define File freopen("fc.in", "r", stdin), freopen("fc.out", "w", stdout)
#define ll long long
#define MX 2005000
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
template <class T> IN T min(T a, T b) {return a < b ? a : b;}
template <class T> IN T max(T a, T b) {return a > b ? a : b;}
int n;
ll del, ans;
ll tree[MX];
int dis[MX], v[MX];
struct INFO {int pos; ll val;};
std::vector <INFO> st[MX];
IN void modify(R int pos, R ll val)
{for (; pos <= n; pos += lbt(pos)) tree[pos] = max(tree[pos], val);}
IN ll query(R int pos)
{
ll ret = 0;
for (; pos; pos -= lbt(pos)) ret = max(ret, tree[pos]);
return ret;
}
IN ll query_init(R int pos)
{
if (pos <= 0) return 0;
return query(pos);
}
int main(void)
{
File;
in(n);
for (R int i = 1; i <= n; ++i) in(dis[i]);
for (R int i = 1; i <= n; ++i) in(v[i]);
for (R int i = 1; i <= n; ++i)
{
for (R int j = st[i].size() - 1; ~j; --j) modify(st[i][j].pos, st[i][j].val);
ll res = query_init(i - dis[i]);
ans = max(ans, res + 1ll * dis[i] * v[i]);
st[i + dis[i]].push_back({i, res + 1ll * dis[i] * v[i]});
}
printf("%lld", ans);
}
PS:
用windows的同学注意了, 如果你对拍用了 f c fc fc命令请把这个文件编译出来的exe删掉…本文件夹里的比path里的优先级更高。