[FJWC 20190212] T1 全连

并没有传送门

题目描述

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) (iti;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,i1],max(ti,tj)ij(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里的优先级更高。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值