【JZOJ4249】游戏【贪心】
题目大意:
题目链接:https://jzoj.net/senior/#main/show/4249
一个长度为的数列,每次可以选择前面任意一个位置跳到那里,价值为你所在的位置。求跳到的最大价值。
思路:
证明:每次选择 其中 表示你所在的位置。
先设起点是0。
那么假设是最大价值的点,但是最优解应该先跳到,且下一次将跳到,且。
那么从0跳到的价值是,跳到的价值是。
从跳到的价值是,从跳到的价值是。
明显从跳到的价值比从跳到的价值大。
那么如果,那么跳到是更合法的。
移项,只要就更合法。
设,有
不等号右侧合并同类项得,即
因为(已经假设是最大价值的点),所以
所以有
证毕。
那么直接单调队列记录最大值即可。
代码:
#include <cstdio>
#include <queue>
#define mp make_pair
using namespace std;
int n,ans,x,y,last;
deque<pair<int,int> > q;
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%d",&x);
while (q.size()&&q.back().first<x) q.pop_back(); //保证单调
q.push_back(mp(x,i));
}
while (q.size())
{
x=q.front().first;
y=q.front().second;
q.pop_front();
ans+=x*(y-last); //计算价值
last=y;
}
printf("%d\n",ans);
return 0;
}