出题人的手环(求逆序对数)

题目

题意:

  出题人的妹子送了出题人一个手环,这个手环上有 n 个珠子,每个珠子上有一个数。

有一天,出题人和妹子分手了,想把这个手环从两个珠子间切开,并按顺时针顺序展开成一条链。

可以发现,这条链一共有 n 种可能性。求这 n 种可能性的逆序对数之积模 1000000007。

思路:

  找出第一个排列的逆序对数(树状数组+离散化),之后每次将最后一个数减去比他大的,加上比他小的就是下一个序列的逆序对数。

  WA点: 减去再加上之后的数 可能小于0,并且要long long

 1 #include<iostream>
 2 #include<cstdio>
 3 #include <cctype>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<cmath>
 7 #include<string>
 8 #include<cmath>
 9 #include<set>
10 #include<vector>
11 #include<stack>
12 #include<queue>
13 #include<map>
14 using namespace std;
15 #define ll long long
16 #define mem(a,x) memset(a,x,sizeof(a))
17 #define se second
18 #define fi first
19 const ll mod=1e9+7;
20 const int INF= 0x3f3f3f3f;
21 const int N=2e5+5;
22 
23 int a[N],c[N];
24 int n;
25 struct node
26 {
27     int v,p;
28 }aa[N];
29 
30 bool cmp(node x,node y)
31 {
32     return x.v<y.v;
33 }
34 
35 int lowbit(int i) {
36     return i&-i;
37 }
38 void add(int x,ll k)
39 {
40     for(int i=x;i<=n;i+=lowbit(i)) c[i]=(c[i]+k)%mod;
41 }
42 ll sum(ll x)
43 {
44     ll sum=0;
45     for(ll i=x;i>0;i-=lowbit(i)) sum=(sum+c[i])%mod;
46     return sum;
47 }
48 
49 
50 int main()
51 {
52     cin>>n;
53     for(int i=1;i<=n;i++) scanf("%lld",&aa[i].v),aa[i].p=i;
54     
55     sort(aa+1,aa+1+n,cmp);
56     ll cnt=0;
57     for(int i=1; i<=n; i++)
58     {
59         if(aa[i].v != aa[i-1].v) {
60             cnt++;
61         }
62         a[aa[i].p] = cnt;
63     }
64     
65     ll ans=0;
66     for(int i=1;i<=n;i++)
67     {
68         add(a[i],1);
69         ans = (ans+i-sum(a[i])+mod )%mod;
70     }
71     
72     ll ans1=ans;
73     for(int i=1;i<n;i++)
74     {
75         ans=(ans-sum(a[i]-1) +mod )%mod;
76         ans=(ans+n-sum(a[i])+mod )%mod;
77         ans1=( ans1*ans)  %mod;
78     }
79     printf("%lld
",ans1);
80 }
View Code
原文地址:https://www.cnblogs.com/thunder-110/p/10295064.html