游戏

Posted on 2019-02-03 09:49  Mocking_Jimmy  阅读(146)  评论(0编辑  收藏  举报

1月30日

Description

WYF从小就爱乱顶,但是顶是会造成位移的。他之前水平有限,每次只能顶出的位移,也就是从一个整点顶到另一个整点上。我们现在将之简化到数轴上,即从 一个整点可以顶到与自己相隔在之内的数轴上的整点上。现在WYF的头变多了,于是他能顶到更远的地方,他能顶到任意整点上。现在他在玩一个游戏,这个游 戏里他只能向正方向顶,同时如果他从i顶到j,他将得到 \(a[j] \times (j - i)\) 的分数,其中a[j]j点上的分数,且要求j > i, 他最后必须停在n上。

现给出1~n上的所有分数,原点没有分数。他现在在原点,没有分。WYF想知道他最多能得多少分。

Input

第一行一个整数n。

第二行有n个整数,其中第i个数表示a[j]

Output

一个整数,表示WYF最多能得到的分数。

Sample Input

3
1 1 50

Sample Output

150

Data Constraint

对于60%的数据,n<=1000;

对于100%的数据,n<=100000,0<=a[j]<=50。

Solution

  • 【我的解法】

比赛时我没想太多,就直接看着60%分数 \(n^2\) dp水了60分。

#include<cstdio>
#include<algorithm>
using namespace std;

int n,a[100001],f[100001];

int main()
{
	freopen("game.in","r",stdin);
	freopen("game.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for(int j=1;j<=n;j++)
		for(int i=0;i<j;i++)
			f[j]=max(f[j],(j-i)*a[j]+f[i]);
	printf("%d",f[n]);
	fclose(stdin);
	fclose(stdout);
	return 0;
}
  • 【玄学正解】

正解是建立在刚刚的dp之上的。要进行非常玄学的优化,叫斜率优化。我引用一下题解。

对于到达的每个点,若要知道应该从哪个点过来,则要比较从两个不同地方过来的答案进行比较。最后比较式整理成类似于 \(\dfrac{f[i] – f[j]}{i – j} > ?\) 的形式。之后可以将(i, f[i])变为二维上的一点,比较式就成为了两点间的斜率是否大于一个数。由于 i 是从小到大枚举的则计算出一个f[i]时就把它插入到二维平面里,之后只需维护斜率下降的一段(斜率上升的一段不需要考虑),用栈来存储点,维护凸包总时间复杂度为 \(O(n)\) ,找最好节点用二分。总时间复杂度为 \(O(n\ log\ n)\)


\(by\) 北师大实验

显然我没有看懂,于是我询问了另一位大佬,他告诉我两个字:贪心。

于是我就AC了。。。

#include<cstdio>
using namespace std;

int n,a[100001],ans,curr;

int main()
{
	freopen("game.in","r",stdin);
	freopen("game.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	curr=n;
	for(int i=n;i>=0;i--)
	{
		if(a[i]<a[curr])
			continue;
		ans+=(curr-i)*a[curr];
		curr=i;
	}
	ans+=curr*a[curr];
	printf("%d",ans);
	fclose(stdin);
	fclose(stdout);
	return 0;
}

斜率优化这玩意我还是先放一放。。。