2021国庆CSP/NOIP冲刺营 Contest06 B. 树苗

【题意】

给定一个长度为偶数的1-n的排列

求最大化$\sum_{i=1}^{n-1}|p_{i+1}-p_i|$,在满足上式最大时的最小操作次数

【分析】

显然我们会贪心的考虑让数列放成

小大小大小大 / 大小大小大小 这样的形式

这样除去最左最右两个位置,每个位置的贡献都是2次,大正小负

那么我们就应该把第$\frac{n}{2}$个和第$\frac{n}{2}+1$个分别放在左右

然后考虑不在自己位置上的有多少个也就是需要多少次调换

【代码】

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
int n,a[maxn],b[maxn];
int main()
{

    int T,P;
    scanf("%d%d",&T,&P);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        int mid=n/2;
        ll sum=0;
        for(int i=mid+2;i<=n;i++) sum+=2ll*i;
        for(int i=1;i<mid;i++) sum-=2ll*i;
        sum++;
        if(P==0) printf("%lld\n",sum);
        else
        {
            int res=0,res1=0;
            for(int i=1;i<=n;i++) b[i]=a[i]; 
            if(b[1]!=mid)
            {   
                res++;
                for(int i=2;i<=n;i++)
                    if(b[i]==mid) swap(b[1],b[i]);
            }
            if(b[n]!=mid+1)
            {
                res++;
                for(int i=1;i<n;i++)
                    if(b[i]==mid+1) swap(b[i],b[n]);
            }
            for(int i=2;i<=n;i+=2)
                if(b[i]<mid) res++;
            res1=res; res=0;
            for(int i=1;i<=n;i++) b[i]=a[i];
            if(b[1]!=mid+1)
            {   
                res++;
                for(int i=2;i<=n;i++)
                    if(b[i]==mid+1) swap(b[1],b[i]);
            }
            if(b[n]!=mid)
            {
                res++;
                for(int i=1;i<n;i++)
                    if(b[i]==mid) swap(b[i],b[n]);
            }
            for(int i=2;i<=n;i+=2)
                if(b[i]>mid) res++;     
            printf("%d\n",min(res1,res));
        }
    }
    return 0;
}

 

posted @ 2021-11-08 13:38  andyc_03  阅读(37)  评论(0编辑  收藏  举报