题目大意
给出长度为
n
(
1
≤
n
≤
1
0
3
)
n(1\leq n \leq 10^3)
n(1≤n≤103) 的数组
w
w
w 和
k
(
−
1
0
6
≤
k
≤
1
0
6
)
k(-10^6\leq k\leq 10^6)
k(−106≤k≤106)。
要求构造一个排列
a
a
a ,连边
(
i
,
a
i
)
(i,a_i)
(i,ai),显然的,会构成一个个环,要求至少一个环权值
w
i
w_i
wi 之和大于
k
k
k。
且该排列中逆序数对最少。
题解
最优解及计算方法
显然的,为了使逆序数对最少,
我们仅对一个符合条件的环进行操作。其他的位置
a
i
=
i
a_i=i
ai=i。
考虑逆序数对最小的情况,
我们构造
p
a
i
=
a
i
+
1
(
1
≤
i
<
s
i
z
)
p
s
i
z
=
a
1
p_{a_i}=a_{i+1}(1\leq i<siz)\ p_{siz}=a_1
pai=ai+1(1≤i<siz) psiz=a1
a
1
a_1
a1左边的数或
a
n
a_n
an 右边的数没有贡献,
环里的数除了最右边每个贡献为
1
1
1 ,
a
1
≤
i
≤
a
n
a_1 \leq i \leq a_n
a1≤i≤an且不在环中的数贡献为
2
2
2 .
a
n
s
=
s
i
z
−
1
+
(
n
−
s
i
z
−
(
a
1
−
1
)
−
(
n
−
a
n
)
)
∗
2
=
2
∗
(
a
n
−
a
1
)
−
l
+
1
ans=siz-1+(n-siz-(a_1-1)-(n-a_n))*2=2*(a_n-a_1)-l+1
ans=siz−1+(n−siz−(a1−1)−(n−an))∗2=2∗(an−a1)−l+1
一个性质
若左右皆固定,则个数越多越好。
我们发现在固定左端点时,环中个数固定的情况下,右端点加入该环,造成贡献为
−
1
-1
−1 。
所以仅当加入右端点后至少还能使得一个元素加入,
才是一个优秀的解
左端点同理
所以我们可以看出左端点和右端点必大于零。
实现
枚举三个维度复杂度为
O
(
N
3
)
O(N^3)
O(N3),被卡掉了。
我们发现有大量重复的计算,考虑使用数据结构优化。
在环中的元素有两类。
①:
w
i
>
=
0
w_i>= 0
wi>=0 一定要加入
②:
w
i
<
0
w_i<0
wi<0,用来凑数的。
想要②类足够多,优先加入权值大的。
确定使用的数据结构为带排序的优先队列。
我们将
w
i
<
0
w_i<0
wi<0 的元素加入优先队列
q
1
q1
q1,每次找到使得当前总值
>
k
>k
>k 的数据量。
加入答案队列
q
q
q。
由于之后可能会出现更大的负权值,所以我们要将预备列和答案队列维护交换一下使得
q
1
q1
q1 内的元素严格小于
q
q
q。
参考代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+5,M=2e6+5;
const int inf=2e6;
int f[N];
priority_queue<int> q,q1;
int n,m,Ans=inf,tot;
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&f[i]);
if(f[i]>=m)
tot=1;
}
if(tot)
{
puts("0");
return 0;
}
for(int l=1;l<=n;l++)
{
while(q.size())
q.pop();
while(q1.size())
q1.pop();
int ans=0,siz=0;
if(f[l]>0)
for(int r=l;r<=n;r++)
{
if(f[r]>0)
{
siz++;
ans+=f[r];
int A=ans-m,c=siz;
if(A<0)
continue;
while(q1.size() && q.size() && q1.top()>-q.top()) //q中数据加负号使得栈顶为最小元素
{ //维护答案队列
int a=q1.top();
int b=q.top();
q1.pop();
q.pop();
q.push(-a);
q1.push(-b);
A+=b;
A+=a;
}
while(q1.size() && A+q1.top()>=0) //加入新答案
{
int a=q1.top();
q1.pop();
q.push(-a);
A+=a;
siz++;
}
Ans=min(2*(r-l)-siz+1,Ans);
}
else
q1.push(f[r]);
}
}
if(Ans==inf) //不存在权值和大于k
puts("-1");
else
printf("%d\n",Ans);
}