模拟赛 序列

解题思路

显然,如果将$a_i$变为序列以外的数,相比于变为序列中的数而言,代价一定是较大的。所以说一定是将$a_i$变为序列内的其他数。

显然,对于每一个$a_i$,只有第一次出现的$a_i$会对数组$c$产生影响。如果将第一次出现的$a_i$改为其他值,那么对于数值为$a_i$的数,只有在下一次$a_i$的出现会对数组$c$产生影响。所以我们只需要存储$a_i$的第一次出现和第二次出现的位置即可。

接下来,我们开始继续考虑$a_i$对代价所产生的影响。显然,对于第一次出现的$a_i$,它对代价的贡献为$i+(i+1)+(i+2)+…+n$,在这里将它记为S(i)。

最后只剩下对于$a_i$的变化所引起的代价改变的讨论了。我们假设将$a_i$变为$a_j$,(假设$a_j$也是第一次出现),且$a_i$的下一次出现为$a_k$,针对$i$与$j$的大小进行分类讨论。

第一种情况 j<i

略微推导可以得知,更改所造成变化的贡献为$|a_i-a_j|+S(k)-S(i)$,$S(k)$与$S(i)$都是确定的值,因此只要找到与$a_i$最接近的$a_j$即可。

第二种情况 j>i

同上推导可知,更改造成的变化的贡献为
$$|a_i-a_j|-S(i)+S(k)-S(j)+S(i)=|a_i-a_j|+S(k)-S(j)$$

在讨论的过程中,为了方便,我们对于$a_i,a_j$的大小进行进一步讨论(将绝对值去掉)。

a[j]>a[i]

$$=S(k)-a_i+a_j-S(j)$$

接下来对于变量我们可以用一个树状数组来维护$a_j-S(j)$的最大值或$S(j)-a_j$的最小值即可。

a[j]<a[i]

同上

至此讨论完成

代码

#pragma GCC optimize(1)
#pragma GCC optimize(3)
#pragma GCC optimize(2)
#include <iostream>//抄
#include <stdio.h>
#include <algorithm>
#include <cstring>
#include <set>
#include <map>
#include <vector>

using namespace std;
const int N=5e5+10;

int n,a[N];
map<int,int> m;
set<int> s;
vector<int> V[N];
int v[N];
long long ans=0;
struct bit{
    long long c[N];
    bit(){
        memset(c,0xcf,sizeof c);
    }
    int lowbit(int x){
        return x&(-x);
    }
    void add(int k,long long x){
        for(;k<=N;k+=lowbit(k)){
            c[k]=max(c[k],x);
        }
    }
    long long query(int x){
        long long ans=0xcfcfcfcfcfcfcfcf;
        for(;x;x-=lowbit(x)){
            ans=max(ans,c[x]);
        }
        return ans;
    }
}T1,T2;
long long sum(int l,int r){
    if(l>r) return 0;
    return (long long)(l+r)*(r-l+1)/2;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    int id=0;
    for(int i=1;i<=n;i++){
        if(!m.count(a[i])) m[a[i]]=++id;
        ans+=(long long )i*id;
        if(V[m[a[i]]].size()<2) V[m[a[i]]].push_back(i),v[i]=V[m[a[i]]].size();
    }
    vector<int> TMP(n);
    for(int i=0;i<n;i++) TMP[i]=a[i+1];
    sort(TMP.begin(),TMP.end());
    auto ed=unique(TMP.begin(),TMP.end());
    for(int i=1;i<=id;i++){
        if(V[i].size()<2) V[i].push_back(n+1);
    }
    long long res=ans;
    s.insert(a[1]);
    for(int i=2;i<=n;i++){
        if(v[i]==1){
            int ID=m[a[i]];
            auto it=s.lower_bound(a[i]);
            int cost=2e9;
            if(it!=s.end()) cost=min(cost,*it-a[i]);
            if(it!=s.begin()) it--,cost=min(cost,a[i]-*it);
            ans=min(ans,res-sum(V[ID][0],V[ID][1]-1)+cost);
            s.insert(a[i]);
        }
    }
    if(v[n]==1){
        ans=min(ans,res-n);
        int idx=lower_bound(TMP.begin(),ed,a[n])-TMP.begin()+1;
        T1.add(id-idx+1,n-a[n]);
        T2.add(idx,n+a[n]);
    }
    for(int i=n-1;i>=1;i--){
        if(v[i]==1){
            int ID=m[a[i]];
            int p=V[ID][1];
            int idx=lower_bound(TMP.begin(),ed,a[i])-TMP.begin()+1;
            long long res1=res-(T1.query(id-idx)-sum(p,n)+a[i]);
            long long res2=res-(T2.query(idx-1)-sum(p,n)-a[i]);
            ans=min(ans,res1);
            ans=min(ans,res2);
            T1.add(id-idx+1,sum(i,n)-a[i]);
            T2.add(idx,sum(i,n)+a[i]);
        }
    }
    printf("%lld\n",ans);
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇