MX 基础赛 D 题讲解

CheZiHe929 / 2024-06-10 / 原文

D. 求和(mex)

link

考虑每个 \(i(0 \le i \le n)\) 成为 mex 的次数。

此时我们需要满足在 mex 为 \(i\) 的序列中 \([1,i-1]\) 都出现一次且 \(i\) 未出现。

我们假设 \([0,i-1]\) 的位置的最小值为 \(l\),最大值为 \(r\)

需要考虑 \(i\) 值所处的位置,记为 \(w_i\)

  • \(l\le w_i \le r\)

不难发现此种情况下 \(i\) 不可能成为任何一个序列的 mex,因为不存在任何一个子序列满足 \([1,i-1]\) 都出现一次且 \(i\) 未出现。

  • \(w_i < l\)

分别考虑 \([1,i]\) 序列的左右端点所有可能的情况,左端点的可能数为 \(l-w_i\)(即左端点为 \([w_i+1,l]\) 中的任意一点),右端点的可能数为 \(n-r+1\)(即右端点为 \([r,n]\) 中的任意一点)。

则此种情况下的答案为 \((l-w_i)\times(n-r+1)\)

  • \(w_i > r\)

同理,答案为 \(l\times(w_i-r)\)

Example:\(5,2,4,1,0,6,3,7\)

代码

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define debug puts("#CheZiHe929")
#define Time std::cout<<1.0*clock()/CLOCKS_PER_SEC<<'s'<<endl;
#define Memory std::cout<<abs(&mst - &men)/1024.0/1024<<"MB"<<endl;
const int MAXN=1e6+5;

inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}return x*f;}
inline void print(int x){char st[105];int top=0;if(x==0)putchar('0');if(x<0)putchar('-');while(x){if(x>0)st[++top]=x%10+48;else st[++top]=-(x%10)+48;x/=10;}while(top)putchar(st[top--]);}
inline void println(int x){print(x);putchar('\n');}
inline void printsp(int x){print(x);putchar(' ');}
inline void put(int x,int i,int n){i==n?println(x):printsp(x);}
inline void IOS(){std::ios::sync_with_stdio(false),std::cin.tie(0),std::cout.tie(0);}

bool mst;
int n,a[MAXN],w[MAXN];
bool men;

signed main(){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);

	n=read();
	for(int i=1;i<=n;i++){
		a[i]=read();
		w[a[i]]=i;
	}
	
	int l=w[0],r=w[0],ans=0;//0 对答案无贡献,直接从 1 开始考虑
	for(int i=1;i<=n-1;i++){
		if(w[i]>=l&&w[i]<=r)continue;
		else if(w[i]<l)ans+=(l-w[i])*(n-r+1)*i;
		else ans+=l*(w[i]-r)*i;
		
		l=std::min(l,w[i]);
		r=std::max(r,w[i]);
	}
	ans+=n;
	println(ans);

	return 0;
}