逸一时,误一世!|

MistZero

园龄:5年5个月粉丝:8关注:3

P4105 南园满地堆轻絮 Sol

先放结论:答案是 max{aiaj}(i<j, aiaj)2

虽然说考场上贪心基本猜个结论就走人,不用证明,但是平时还是要会证明贪心正确性的。

O(nlogn) 做法:二分 + 贪心

首先这道题看到最大值最小可以想到二分。
那么想到二分答案,即这个最小差值。
这个时候可以将问题简化为:存在一个答案 ans,将序列所有元素变为 ai±ans,使得序列单调不减。

所以转化为判定问题,想到贪心策略。

check 函数中,记录扫到当前的 aimax{ajans} (j<i),如果当前 ai+ans<max 那么一定无解。

证明挺显然的。

由于这里 ans 原来是差值的 max,即 ±[0,ans] 都是可以的。上界为 ai+ans,下界为 aians。此时前面的下界大于此时的上界,可以 break。


O(n) 做法:贪心

贪心策略:找最大逆序对差值。

  1. 为什么是逆序对?

想一下 b 的变化图像一定有横坐标和纵坐标正相关。那么此时最劣情况必然是 a 的变化负相关。那么这差不多就是逆序对的定义。

  1. 为什么是最大逆序对?

最大逆序对的波动是最大的,相应地,需要满足的 ans 也是最大的。此时必然取中点答案最小,文章开头结论正确。

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int N = 5e6 + 10;
int n, sa, sb, sc, sd, MOD, Max, res, a[N];

inline int f(int x) {
  int fi = sa * x % MOD * x % MOD * x % MOD;
  int se = sb * x % MOD * x % MOD;
  int th = sc * x % MOD;
  return (fi + se + th + sd) % MOD;
}

signed main() {
  cin >> n >> sa >> sb >> sc >> sd >> a[1] >> MOD;
  Max = a[1];
  for (int i = 2; i <= n; ++i) {
    a[i] = (f(a[i - 1]) + f(a[i - 2])) % MOD;
    if (a[i] <= Max) res = max(res, Max - a[i]);
    Max = max(Max, a[i]);
  }
  cout << (res + 1) / 2 << endl;
  return 0;
}

本文作者:MistZero

本文链接:https://www.cnblogs.com/MistZero/p/P4105-Sol.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   MistZero  阅读(20)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起