P1667 数列(置换&前缀和)
Posted Harris-H
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1667 数列(置换&前缀和)相关的知识,希望对你有一定的参考价值。
P1667 数列(置换&前缀和)
考虑对前缀和操作。
s
l
−
1
+
=
x
s
l
=
s
l
+
x
−
x
s
r
−
=
x
s
r
+
1
=
s
r
+
1
+
x
−
x
\\large s_{l-1}+=x \\\\ \\large s_l = s_l +x -x \\\\ \\large s_{r}-=x \\\\ \\large s_{r+1}= s_{r+1} + x-x
sl−1+=xsl=sl+x−xsr−=xsr+1=sr+1+x−x
原
s
r
−
s
l
−
1
=
x
\\large s_r-s_{l-1}=x
sr−sl−1=x
现在 s l − 1 − s r = x \\large s_{l-1}-s_r=x sl−1−sr=x,其他未变。
所以相当于交换操作。
题意转换为交换最少次数变成递增序。
根据置换的知识,答案就是: n − m n-m n−m。
为什么是 m m m呢?,因为一个长为 x x x的置换环最少只需要 x − 1 x-1 x−1次,所以多一个置换环相当于减少一次交换次数。
m m m是置换环的个数。
也可以贪心找。先离散化下,预处理第 i i i小的前缀和所在的位置 c [ i ] c[i] c[i],然后每次贪心就可以了。
或者也可以搜索,找到环就就是一个置换环。
// Problem: P1667 数列
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P1667
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// Date: 2021-07-23 20:21:23
// --------by Herio--------
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=1e5+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define ios ios::sync_with_stdio(false),cin.tie(0)
void Print(int *a,int n){
for(int i=1;i<n;i++)
printf("%d ",a[i]);
printf("%d\\n",a[n]);
}
ll a[N],b[N],p[N],c[N];
int n;
bool cmp(int x,int y){
return a[x]<a[y];
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]),a[i]+=a[i-1],b[i]=a[i];p[i]=i;
}
sort(b+1,b+n+1);
if(b[1]<=0) return puts("-1"),0;
for(int i=2;i<=n;i++) if(b[i]==b[i-1]) return puts("-1"),0;
sort(p+1,p+n+1,cmp);
for(int i=1;i<=n;i++) c[p[i]]=i;
int ans=0;
for(int i=1;i<=n;i++)
while(c[i]!=i) swap(c[i],c[c[i]]),ans++;
printf("%d\\n",ans);
return 0;
}
以上是关于P1667 数列(置换&前缀和)的主要内容,如果未能解决你的问题,请参考以下文章