标签:IOI2019 排列 return int len 1000001 鞋子 include
$[IOI2019]$排列鞋子
链接:https://www.luogu.com.cn/problem/P5749
题目描述:
将一个序列$A$交换到满足对于任意的$i(1<=i<=n/2)$满足
$a_{i}=-a_{i\times 2}$且$a_{i}<0$,求至少要交换多少次。
题解:交换多少次就等价于交换得到的排列的逆序对数量,我们可以从这构造一个这样的排列入手。
引理$1$:每一组$a_{i}$相同的左脚鞋与右脚鞋匹配时,从小到大依次匹配最优。
证明:对于每一组匹配$(i,j)$,其贡献为剩余的满足$[k<=i]$的与满足$[k<=j]$的和。因为我们每一次一定是贪心的选取两个贡献最少的,所以每一次要求出满足
$[k<=i]+[k<=j]$的最小$(i,j)$。考虑反证:假设我们选取$a_{i}$相同的不依次匹配的数对$(i,j)$更优,令$a_{i}$依次匹配时$i$匹配了$t$,则$t<=j$。那么$[k<=i]+[k<=t]<=[k<=i]+[k<=j]$,则答案此时便的更劣了,矛盾,则该假设不成立。
引理$2$:按照引理$1$匹配之后,令$b_{i}$表示左脚鞋$i$匹配的数,则以$min(a_{i},a_{b_{i}})$按顺序排列更优。
证明:~~不会,打表吧~~。
根据上述引理:我们可以将逆序对最小的排列求出,树状数组求该排列的逆序对即可。
```
#include
#include
#include
#include
using namespace std;
struct node
{
int l,r;
bool operator < (const node &t)const
{
return min(l,r)<min(t.l,t.r); }="" };="" node="" t[1000001];="" vector<int="">s[1000001];
int n,a[1000001],len,d[2000001];
long long c[1000001],S,ans;
int lowbit(int x)
{
return x&(-x);
}
void add(int x,int y)
{
for (;x<=n;x+=lowbit(x))
c[x]+=y;
return;
}
long long sum(int x)
{
S=0;
for (;x>=1;x-=lowbit(x))
S+=c[x];
return S;
}
int main()
{
cin>>n;
n*=2;
for (int i=1;i<=n;++i)
{
cin>>a[i];
if (a[i]<0)
s[-a[i]].push_back(i);
}
for (int i=n;i>=1;--i)
{
if (a[i]>0)
{
t[++len].l=s[a[i]][s[a[i]].size()-1];
s[a[i]].pop_back();
t[len].r=i;
}
}
sort(t+1,t+n/2+1);
for (int i=1;i<=n/2;++i)
{
d[i*2-1]=t[i].l;
d[i*2]=t[i].r;
}
for (int i=1;i<=n;++i)
{
ans+=sum(n+1-d[i]);
add(n+1-d[i],1);
}
cout<
标签:IOI2019,
排列,
return,
int,
len,
1000001,
鞋子,
include
From: https://www.cnblogs.com/zhouhuanyi/p/16983466.html