連接:https://ac.nowcoder.com/acm/contest/358/D
來源:牛客網
html
第一行一個數 n,表示珠子個數。
接下來一行 n 個數,以順時針順序給出每一個珠子上的整數
一個數,表示答案。
n<=200000,-10^9<=珠子上的整數<=10^9。
思路:
我的以爲仍是一個很不錯的題目。
首先,由於數值範圍比較大,先離散化一下。 (不會離散化的點此去學
其次先根據離散化後的數組標記下求一個前綴和,前綴和 sum[i] 維護的是 離散化後的數組(下面成爲新數組)中的1~i中累計的個數和,須要多開一個vis數組,
而後先根據樹狀數組來求出新數組的逆序對的總數。(具體求法和細節看code和註釋)
而後咱們把當前新數組中的第一個數放在最後一個位置,這樣對一個數組的逆序對總和的影響是 減去 2~n位置中小於a[1]的個數,加上2~n位置中大於a[1]的個數,
而這剛好能夠用咱們剛剛求得前綴和來解決。
而後每個調整後得數組的總和乘起來,記得取模就行了 (算法學習(二)——樹狀數組求逆序數)
細節見個人代碼:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #include <vector> #define sz(a) int(a.size()) #define all(a) a.begin(), a.end() #define rep(i,x,n) for(int i=x;i<n;i++) #define repd(i,x,n) for(int i=x;i<=n;i++) #define pii pair<int,int> #define pll pair<long long ,long long> #define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) #define MS0(X) memset((X), 0, sizeof((X))) #define MSC0(X) memset((X), '\0', sizeof((X))) #define pb push_back #define mp make_pair #define fi first #define se second #define eps 1e-6 #define gg(x) getInt(&x) #define db(x) cout<<"== "<<x<<" =="<<endl; using namespace std; typedef long long ll; inline void getInt(int* p); const int maxn=1000010; const int inf=0x3f3f3f3f; /*** TEMPLATE CODE * * STARTS HERE ***/ int n; ll a[maxn]; ll b[maxn]; ll tree[maxn]; ll vis[maxn]; ll sum[maxn]; const ll mod=1000000007ll; int lowbit(int x) { return x&(-1*x); } void add(int i) { while(i<=maxn) { tree[i]+=1; i+=lowbit(i); } } ll query(int i) { ll res=0; while(i>0) { res+=tree[i]; i-=lowbit(i); } return res; } int main() { gbtb; cin>>n; repd(i,1,n) { cin>>a[i]; b[i]=a[i]; } sort(b+1,b+1+n);// 輔組數組的排序 int cnt=unique(b+1,b+1+n)-b-1; // 去重 repd(i,1,n) { a[i]=lower_bound(b+1,b+1+cnt,a[i])-b; // 離散化掛的核心code vis[a[i]]++;// 標記 } repd(i,1,n) { sum[i]=sum[i-1]+vis[i]; // 求前綴和,sum[i]表明1~的個數和。 } ll tot=0ll;// 一個數組總的逆序對總和。 repd(i,1,n) { add(a[i]); tot+=i-query(a[i]); // quert函數返回的是這個數組中小於等於a[i]的數量 // 那麼i-quert 就是 數組中大於a[i]的數量,那麼就是逆序對的數量。 // 樹狀數組 中維護的是一個單點修改,區間查詢的樹狀數組 // 咱們add(a[i]) 就是向樹狀數組中增長一個a[i]出現的次數。 // query(a[i]) 查詢的就是 1 ~ a[i] 出現的數量總和。 tot=(tot+mod)%mod; } ll ans=tot; for(int i=1;i<=n-1;i++) { tot=tot-(sum[a[i]-1])+n-sum[a[i]]; // -(sum[a[i]-1]) 是減去比a[i]小的個數,即去掉了以a[i]爲左的逆序對, // +n-sum[a[i]]; 是加上 以a[i]爲右的逆序對,即加上數組中有多少個數大於a[i] tot=(tot+mod)%mod; ans*=tot; ans=(ans+mod)%mod; } cout<<ans<<endl; return 0; } inline void getInt(int* p) { char ch; do { ch = getchar(); } while (ch == ' ' || ch == '\n'); if (ch == '-') { *p = -(getchar() - '0'); while ((ch = getchar()) >= '0' && ch <= '9') { *p = *p * 10 - ch + '0'; } } else { *p = ch - '0'; while ((ch = getchar()) >= '0' && ch <= '9') { *p = *p * 10 + ch - '0'; } } }
參考了這位大佬的題解:https://blog.csdn.net/qq_40655981/article/details/86547600ios