思路:树状数组,l[i]表示,表示 i 处结尾的长度为2的升序子序列种数(即正序对数量),
r[i]表示表示, i 处为开头向后,长度为2的降序子序列数量(正序对数量)
12××:l[i]*C((n-i-r[i]),2);
1234:长度为三的升序子序列种数*(n-i-r[i]);
所以,1243=12××-1234;
参考源自这里
#include <stdio.h>
#include <algorithm>
#include <string.h>
#define ll long long
#define pa pair<int,int>
#define P 16777216
using namespace std;
int n;
int a[200005];
ll l[200005],r[200005],t[200005];
void add(int x,int y)
{
for(int i=x;i<=n;i+=(i&-i))
t[i]+=y;
}
ll query(int x)
{
ll ans=0;
for(int i=x;i>0;i-=(i&-i))
ans+=t[i];
return ans;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
//query(a[i])计算的是以i为结尾长度为二的升序子序列种数
l[i]=query(a[i]);
r[i]=a[i]-l[i]-1;
add(a[i],1);
}
ll res=0;
for(int i=1;i<=n;i++)
res=(res+l[i]*(n-i-r[i])*(n-i-1-r[i])/2)%P;
ll pre=0;
memset(t,0,sizeof(t));
for(int i=1;i<=n;i++){
//query(a[i])计算的是i为结尾长度为三的上升序子序列数
//因为t[]先清零,后储存的是到i长度为二的上升子序列的种数,再加上它自己所以是长度为三的
pre=(pre+query(a[i])*(n-i-r[i]))%P;
add(a[i],l[i]);
}
printf("%lld\n",(res-pre+P)%P);
return 0;
}
get到的取模新方法:a%p==a&(p-1),使用前提是p为2的幂次方。
这样,p-1 的二进制就是一个形如“0000111...”的数,比如,如果p=4,p-1=3,其二进制表示为“0011”,如果p=8,p-1=7,其二进制表示为“0111”,以此类推。将a和p-1进行按位与运算的时候,由于高位都是0,只有低位的1才能决定最终的结果,就相当于对a进行相应数值(即p)的求模运算。