一开始做麻烦了,关键是写麻烦了还没过,好气哦。
这题应该有很多不同的思路。我的想法是计算给出的数组中每一对相邻的数在之后的排列(Permutation)中距离的变化,然后只要以第一个排列的答案为基准,加上之后排列的距离变化就是后面排列的答案了。
那么距离是如何变化的呢,我们设一对相邻的数中比较小的数是,比较大的数是 ,那么他们在第一个排列中的位置就是这样的: 在第一个一直到第个排列中,和的位置都没有发生变化,自然距离也不变。但在第个排列中,成了第一个数:
与的距离增加了。
在第到个排列中,与中的某一个数会在最前面,所以与的距离比最开始少 1。
在第个排列中,r 跑到了最前面: 注意此时 l 的位置依然是,所以距离的变化是
如果我们用一个数组 a 来保存所有排列中答案的变化,那么对于每一对,我们应该做如下三个操作:
由于其中涉及到区间修改,所以我们可以用差分的思想来实现,并且由于只会查询一次,所以用最简单的数组就可以了,具体实现见代码:
#include <iostream>
#define forn(i, n) for (int i = 0; i < (int)(n); ++i)
#define for1(i, n) for (int i = 1; i <= (int)(n); ++i)
#define fore(i, l, r) for (int i = (int)(l); i <= (int)(r); ++i)
#define ford(i, n) for (int i = (int)(n)-1; i >= 0; --i)
#define pb push_back
#define ms(a, x) memset(a, x, sizeof(a))
#define endl '\n'
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
typedef pair<int, int> pii;
const int N=2e5+5;
ll sum[N];
int n,m;
void rgadd(int l,int r,int x){
sum[l]+=x;
sum[r+1]-=x;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>m;
int x,last;
cin>>last;
ll ans=0;
forn(i,m-1){
cin>>x;
int mn=min(x,last),mx=max(x,last);
ans+=mx-mn;
last=x;
if(mx==mn) continue;
rgadd(mn,mn,mn-1);
rgadd(mx,mx,(mn-mx+mn));
if(mx-mn>1)
rgadd(mn+1,mx-1,-1);
}
for1(i,n){
ans+=sum[i];
cout<<an<<' ';
}
return 0;
}