链接:https://ac.nowcoder.com/acm/contest/358/D
来源:牛客网
题目:
出题人的妹子送了出题人一个手环,这个手环上有 n 个珠子,每个珠子上有一个数。
有一天,出题人和妹子分手了,想把这个手环从两个珠子间切开,并按顺时针顺序展开成一条链。
可以发现,这条链一共有 n 种可能性。求这 n 种可能性的逆序对数之积模 1000000007。
输入:
第一行一个数 n,表示珠子个数。
接下来一行 n 个数,以顺时针顺序给出每个珠子上的整数
输出:
一个数,表示答案。
分析:
n种情况无非是每次将第一个元素移到末尾,此时逆序数个数的变化为:当前逆序数总数 - 比 a[1] 小的数的个数 + 比 a[1] 大的个数
第一次的逆序数的总数可以用树状数组计算,但 a[i] 范围太大,n 比较小,于是先将 a[i] 排序后离散化,再处理出比每个数大的数的个数和比它小的数的个数
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MOD = 1e9+7;
const int MAXN = 2e5+55;
LL a[MAXN],b[MAXN],c[MAXN],num1[MAXN],num2[MAXN],n;
inline int lowbit(int x)
{
return x & (-x);
}
void updata(int pos,int val)
{
while(pos <= n)
{
a[pos] += val;
pos += lowbit(pos);
}
}
int query(int pos)
{
int res = 0;
while(pos > 0)
{
res += a[pos];
pos -= lowbit(pos);
}
return res;
}
int main()
{
cin>>n;
for(int i = 0; i < n; ++i)
{
cin>>b[i];
c[i] = b[i];
}
sort(c,c+n);
LL sum = 0; //总的逆序数对
for(int i = 0; i < n; ++i)
{
int pos1 = lower_bound(c,c+n,b[i]) - c;
int pos2 = upper_bound(c,c+n,b[i]) - c;
num1[i] = pos1; //比b[i]小的总个数
num2[i] = n - pos2; //比b[i]大的总个数
sum += pos1 - query(pos1);
updata(pos1+1,1);
}
LL res = sum % MOD;
for(int i = 0; i < n-1; ++i) //注意最后一个数不能再算了
{
sum = ((sum - num1[i] + num2[i])%MOD + MOD) % MOD;
res = (res * sum) % MOD;
}
cout<<res;
return 0;
}