题解:AT_arc077_c [ARC077E] guruguru
思路
提供一种思维难度不高,分块暴力艹的题解。
分析一下发现,\(x\) 可以减少操作次数的无非就三种情况
- \(a_{i-1}<x\le a_{i}\),此时减少 \(x-a_{i-1}-1\) 步操作。
- \(a_{i-1}>a_i\) 且 \(x>a_{i-1}\),此时减少 \(x-a_{i-1}-1\) 步操作。
- \(a_{i-1}>a_i\) 且 \(x\le a_{i}\),此时减少 \(m-a_{i-1}+x-1\) 步操作。
我们把 \(a_{i-1}<a_i\) 和 \(a_{i-1}>a_{i}\) 的点对分成两类。
对于第 \(2\) 种和第 \(3\) 种情况,无非就是全局询问第二类满足 \(a_{i-1}<x\) 的 \(a_{i-1}\) 的个数和和,以及第二类中满足 \(x\le a_i \le m\) 的 \(a_{i}\) 的个数和相对应的 \(a_{i-1}\) 的和。如果记满足关系的个数为 \(c\),\(a_{i-1}\) 的和为 \(sum\),那么第 \(2\) 种情况对答案贡献为 \(c_2\times (x-1)+sum_2\),第 \(3\) 类就是 \(c_3\times (m+x-1)+sum_3\)。
因为询问的跟值域有关,我们可以用值域分块来简单维护个数与和。
而对于第 \(1\) 种情况,\(a_{i-1}<x\le a_{i}\),可以认为是二维偏序关系,套路是按照 \(a_{i-1}\) 排序搞掉第一维,二分出第二维的询问区间,询问区间内 \(a_i\in[x,m]\) 的个数与对应的 \(a_{i-1}\) 的和,很容易想到用教主的魔法的套路,分块+二分,块内前缀和来维护。
复杂度分析默认 \(n,m\) 同阶。
第 \(2\) 类和第 \(3\) 类情况复杂度是 \(O(n\sqrt n)\) 的,第 \(1\) 类情况是 \(O(n\log n+n\sqrt n\log{(\sqrt n)})\),综上来看复杂度为 \(O(n\sqrt n \log n)\) 的,被 \(O(n)\) 正解爆踩。
code
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<climits>
#include<ctime>
#include<cctype>
#include<queue>
#include<vector>
#include<map>
#include<set>
#define int long long
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef __int128 Int;
template<class T>
inline void read(T &x)
{
x=0;short w=1;
char c=getchar();
while(c<'0'||c>'9')
{
if(c=='-') w=-1;
c=getchar();
}
while(c>='0'&&c<='9')
x=(x<<3)+(x<<1)+c-'0',c=getchar();
x=x*w;
}
inline void read(char &x)
{
x=getchar();
while(isspace(x))
x=getchar();
return;
}
inline void read(char *x)
{
char c=getchar();
while(isspace(c)) c=getchar();
while(!isspace(c)&&~c)
*(x++)=c,c=getchar();
*x=0;
}
inline void read(string &x)
{
char c=getchar();x.clear();
while(isspace(c)) c=getchar();
while(!isspace(c)&&~c)
x.push_back(c),c=getchar();
}
inline void read(double &x)
{
x=0;short w=1;
char c=getchar();
while(c<'0'||c>'9')
{
if(c=='-') w=-1;
c=getchar();
}
while(c>='0'&&c<='9')
x=x*10+c-'0',c=getchar();
if(c=='.')
{
c=getchar();double f=0.1;
while(c>='0'&&c<='9')
{
x+=(c-'0')*f,f*=0.1;
c=getchar();
}
}
x=x*w;
}
template<class T>
inline void write(T x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10^'0');
}
inline void write(char c){putchar(c);}
inline void write(string x){for(auto c:x) putchar(c);}
inline void write(char *x){while(*x) putchar(*(x++));}
inline void write(const char *x){while(*x) putchar(*(x++));}
inline void write(double x){printf("%.6lf",x);}
template<class type,class ...T>
inline void read(type &x,T&...y){read(x),read(y...);}
template<class type,class ...T>
inline void write(type x,T ...y){write(x),write(y...);}
const int N=1e5+10,M=350,V=1e5;
int n,m,a[N];
pair<int,int>b[N];
int c[N],d[N];
int fi[N],se[N];
int t=0,k=0;
int Be[N],L[M],R[M],h=0;
int Pos[N],l[N],r[N];
int U[N],id[N],B=0,Cpy[N];
ll Sum[N];
void build(int n)
{
if(!n) return;
int len=sqrt(n);B=(n/len)+bool(n%len);
for(int i=1;i<=n;i++)
{
Pos[i]=(i-1)/len+1;
if(!l[Pos[i]]) l[Pos[i]]=i;
r[Pos[i]]=i;
}
for(int i=1;i<=B;i++)
{
for(int j=l[i];j<=r[i];j++) U[j]=se[j],id[j]=j;
sort(id+l[i],id+r[i]+1,[&](int x,int y){return U[x]<U[y];});
for(int j=l[i];j<=r[i];j++) Cpy[j]=U[id[j]];
for(int j=l[i];j<=r[i];j++) U[j]=Cpy[j];
Sum[l[i]]=fi[id[l[i]]];
for(int j=l[i]+1;j<=r[i];j++) Sum[j]=Sum[j-1]+fi[id[j]];
}
return;
}
inline ll querySum(int p,int q,int x)
{
if(p>q) return 0;
ll res=0;
if(Pos[p]==Pos[q]){
for(int i=p;i<=q;i++)
res+=(se[i]>=x)*fi[i];
}
else{
for(int i=p;i<=r[Pos[p]];i++)
res+=(se[i]>=x)*fi[i];
for(int i=l[Pos[q]];i<=q;i++)
res+=(se[i]>=x)*fi[i];
for(int i=Pos[p]+1;i<=Pos[q]-1;i++)
{
int pos=lower_bound(U+l[i],U+r[i]+1,x)-(U+1);
if(pos<l[i]) res+=Sum[r[i]];
else res+=Sum[r[i]]-Sum[pos];
}
}
return res;
}
inline ll queryCnt(int p,int q,int x)
{
if(p>q) return 0;
ll res=0;
if(Pos[p]==Pos[q]){
for(int i=p;i<=q;i++)
res+=(se[i]>=x);
}
else{
for(int i=p;i<=r[Pos[p]];i++)
res+=(se[i]>=x);
for(int i=l[Pos[q]];i<=q;i++)
res+=(se[i]>=x);
for(int i=Pos[p]+1;i<=Pos[q]-1;i++)
res+=r[i]-(lower_bound(U+l[i],U+r[i]+1,x)-(U+1));
}
return res;
}
void build()
{
int len=sqrt(m);h=(m/len)+bool(m%len);
for(int i=1;i<=m;i++)
{
Be[i]=(i-1)/len+1;
if(!L[Be[i]]) L[Be[i]]=i;
R[Be[i]]=i;
}
return;
}
struct Block{
int C[N],Val[N];
ll Sum[M],Cnt[M];
Block()
{
memset(C,0,sizeof(C));
memset(Val,0,sizeof(Val));
memset(Sum,0,sizeof(Sum));
memset(Cnt,0,sizeof(Cnt));
}
void build(int n,int a[],int b[])
{
for(int j=1;j<=n;j++)
{
++C[a[j]],Val[a[j]]+=b[j];
++Cnt[Be[a[j]]],Sum[Be[a[j]]]+=b[j];
}
}
inline ll querySum(int x)
{
ll res=0;
for(int i=1;i<Be[x];i++)
res+=Sum[i];
for(int i=L[Be[x]];i<=x;i++)
res+=Val[i];
return res;
}
inline ll queryCnt(int x)
{
ll res=0;
for(int i=1;i<Be[x];i++)
res+=Cnt[i];
for(int i=L[Be[x]];i<=x;i++)
res+=C[i];
return res;
}
}C,D;
inline ll query(int x)
{
ll Sum=0;int pos=0;
pos=lower_bound(fi+1,fi+1+k,x)-(fi+1);
Sum+=(x-1)*queryCnt(1,pos,x)-querySum(1,pos,x);
Sum+=(x-1)*C.queryCnt(x-1)-C.querySum(x-1);
Sum+=(m+x-1)*(D.queryCnt(m)-D.queryCnt(x-1))-(D.querySum(m)-D.querySum(x-1));
return Sum;
}
signed main()
{
read(n,m);
for(int i=1;i<=n;i++) read(a[i]);
ll Ans=0;build();
for(int i=2;i<=n;i++)
if(a[i]>=a[i-1]) Ans+=a[i]-a[i-1];
else Ans+=m-a[i-1]+a[i];
for(int i=2;i<=n;i++)
if(a[i]>a[i-1]) b[++k]=make_pair(a[i-1],a[i]);
else if(a[i]<a[i-1]) c[++t]=a[i-1],d[t]=a[i];
sort(b+1,b+1+k);C.build(t,c,c),D.build(t,d,c);
for(int i=1;i<=k;i++)
fi[i]=b[i].first,se[i]=b[i].second;
build(k);
ll Sum=Ans;
for(int x=1;x<=m;x++)
Sum=min(Sum,Ans-query(x));
write(Sum);
return 0;
}

浙公网安备 33010602011771号