P8927 「GMOI R1-T4」Rain

(文章目录)


前言

(大雾 一群神仙构造拆式子。我乱搞想骗分的贪心没有WA就离谱。顺便吐槽一下题意好难懂。我做题得跟用来判SPJ的checker.cpp一起看就离谱。另外祝大家1月1日新年快乐。


题目大意

需要在一条笔直的路上建 nn 个法阵,编号为 1,2,,n1,2,\cdots,n

给定一个长度为 nn 的数组 aa,表示在 a1a_1ana_n 的位置建法阵,要给法阵编号。

需要来检测法阵效果,从 11 号法阵走到 22 号,从 22 号再走到 33 号,直到走到 nn 号,再从 nn 号走回 11 号。

由于法阵的特殊效果,从 ii 个走到 i+1i+1 个的距离是 ai×pai+1×q\left|a_i\times p-a_{i+1}\times q\right|。特别的,从 nn 号走回到 11 号的距离是 an×pa1×q\left|a_n\times p-a_1\times q\right|p,qp,q 是给定的两个常数,ai,ai+1a_i,a_{i+1} 是两个法阵的位置。

来求一下最大的行走距离,并输出对应法阵从 11 号到 nn 号排列方法。
对于 100%100\% 的数据满足 10n10610\le n\le 10^61p,q1051\le p,q \le 10^{5}1ai1051\le a_i\le 10^{5}


思路

暴力深搜 O(nn)\mathcal{O}(n^n),肯定T飞了。考虑优化。由于出题人连大样例的构造方式都不给了,小样例又特别水,所以可以猜测本题应该不会十分困难。

感觉本题好像可以贪心的样子,也没啥其他的思路了,想想试试。如果要贪心,那我就按照这样构造试试:

  • 找最大的放到新序列里
  • 找最小的放到新序列里
  • aa 中删除这两个数

听着很绕,其实就是按照一大一小一大一小···这样排序。测一下小样例,发现不对。然后发现上述情况没有考虑 p,qp,q,感觉这是不是错的原因。之后发现,如果 qq 更大,那么按照小大小大···这么排序更好,因为这可以让大数变得更大,就算大的很小也不亏。所以分类讨论。当 p>qp>q 时按照前者进行运算,否则按照后者进行。

时间复杂度 O(nlogn)O(n\log{n})

代码

#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll MAXN=1e6+5;
ll n,p,q,a[MAXN],b[MAXN];
bool cmp(ll A,ll B){
    return A>B;
}
int main(){
    cin>>n;
    cin>>p>>q;
    for (int i = 1; i <=n ; ++i) {
        cin>>a[i];
    }
    if(p>q){
        sort(a+1,a+n+1);
    }else{
        sort(a+1,a+n+1,cmp);
    }
    ll l=1,r=n;
    ll sz=0;
    while (l<=r){
        b[++sz]=a[l];//放最小/大的
        b[++sz]=a[r];//放最大/小的
        l++;
        r--;
    }
    ll ans=0;
    for (int i = 1; i <n ; ++i) {
        ans+= abs(b[i]*p-b[i+1]*q);
    }
    ans+= abs(b[n]*p-b[1]*q);
    cout<<ans<<endl;
    for (int i = 1; i <=n ; ++i) {
        printf("%lld ",b[i]);
    }
    return 0;
}

总结

通过了分析题面和大胆猜测的出了贪心的做法。同时在经过错误后的分析得出了正解。