这道题是树状数组的另一用法,用值去作为数组的下标。
具体思路:
input :
1
3 1 2 3
3 1 2 3
output:
1
先以其中一个数假设为a为中心,利用树状数组的优势求出这个数a左边比它自己大的数的个数,再求出这个数a的右边比它自己大的个数,分别记为lmin[a],lmax[a],rmin[a],rmax[a];然后结果就是sum+=lmin[i]*rmax[i]+rmin[i]*rmax[i];外层加上一个for循环就OK啦,还不明白么?看看下面的代码,再想想上面说的这段话,很容易理解滴。
还有,做这道题之后,我深刻地意识到,cin不能乱用啊,输入量大的时候,非常容易TLE,恐怖啊!以后注意点
#include<iostream> #define M 100001 #define lowbit(x) x&(-x) using namespace std; int flag[100001],rank[100001],rmin[100001],rmax[100001],lmin[100001],lmax[100001]; int m; int add(int n) { while(n<=M)//注意这里的M是全部的,而不是m { flag[n]++; n+=lowbit(n); } return 0; } int subsum(int n) { int sum=0; while(n>=1) { sum+=flag[n]; n-=lowbit(n); } return sum; } int main(void) { int n,i,j; cin>>n; while(n--) { _int64 sum=0; scanf("%d",&m); for(i=1;i<=m;i++) scanf("%d",&rank[i]);//这里不可以用cin,因为输入量太大,用cin就TLE,输入量达到100000 for(i=1;i<=M;i++) flag[i]=0;//初始化,注意要全数组初始化 for(i=1;i<=m;i++) { lmin[i]=subsum(rank[i]); lmax[i]=i-lmin[i]-1; add(rank[i]); } for(i=1;i<=M;i++) flag[i]=0; for(i=m,j=1;i>=1;i--,j++) { rmin[i]=subsum(rank[i]); rmax[i]=j-1-rmin[i]; add(rank[i]); } // for(i=1;i<m+1;i++) // cout<<lmin[i]<<" "<<lmax[i]<<" "<<rmin[i]<<" "<<rmax[i]<<" "<<endl; for(i=1;i<=m;i++) sum+=lmin[i]*rmax[i]+lmax[i]*rmin[i];//要考虑这里是会溢出的,因为左右如果都为50000,那么相乘就会int溢出 printf("%I64d\n",sum); } return 0; } |