zoukankan      html  css  js  c++  java
  • 【JZOJ4249】游戏【贪心】

    题目大意:

    题目链接:https://jzoj.net/senior/#main/show/4249
    一个长度为nn的数列,每次可以选择前面任意一个位置ii跳到那里,价值为ai×(ia_i imes(i-你所在的位置))。求跳到nn的最大价值。


    思路:

    证明:每次选择max{ai(ijn)}max{a_i(iin jsim n)} 其中jj 表示你所在的位置。

    先设起点是0。
    那么假设ii是最大价值的点,但是最优解应该先跳到jj,且下一次将跳到kk,且j<i<kj<i<k
    那么从0跳到jj的价值是j×ajj imes a_j,跳到ii的价值是i×aii imes a_i
    jj跳到kk的价值是(kj)ak(k-j)a_k,从ii跳到kk的价值是(ki)ak(k-i)a_k
    明显从jj跳到kk的价值比从ii跳到kk的价值大(ij)ak(i-j)a_k
    那么如果i×aij×aj>(ij)aki imes a_i-j imes a_j>(i-j)a_k,那么跳到ii是更合法的。
    移项,只要i×ai>(ij)ak+j×aji imes a_i>(i-j)a_k+j imes a_j就更合法。
    T=max(ak,aj)T=max(a_k,a_j),有(ij)ak+j×aj(ij)T+j×T(i-j)a_k+j imes a_jleq (i-j)T+j imes T
    不等号右侧合并同类项得(ij)ak+j×aj(ij+j)T(i-j)a_k+j imes a_jleq (i-j+j)T,即(ij)ak+j×ajTi(i-j)a_k+j imes a_jleq Ti
    因为ai>Ta_i>T(已经假设ii是最大价值的点),所以i×aI>Tii imes a_I>Ti
    所以有i×ai>Ti(ij)ak+j×aji imes a_i>Tigeq (i-j)a_k+j imes a_j
    证毕。

    那么直接单调队列记录最大值即可。


    代码:

    #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
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    抓取csdn上的各类别的文章 (制作csdn app 二)
    数塔 动态规划
    Android 使用Fragment,ViewPagerIndicator 制作csdn app主要框架
    钥匙计数之二
    FusionCharts简单教程(三)-----如何自定义图表上的工具提示
    位图像素的颜色 携程编程大赛hdu
    Android 仿Win8的metro的UI界面(上)
    Android 省市县 三级联动(android-wheel的使用)
    JDK源码学习系列01----String
    互联网投稿渠道
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998331.html
Copyright © 2011-2022 走看看