标签:
题目,要求找出有多少对这样的东西,四个数,并且满足num[a]<num[b] &&num[c]>num[d]
要做这题,首先要懂得用树状数组,我设,下面的小于和大于都是严格的小于和大于
dpL_min[i]:表示在第i个数往左,(不包括第i个),有多少个数是少于num[i]的
dpL_max[i]:表示在第i个数往左,(不包括第i个),有多少个数是大于num[i]的
dpR_min[i]:表示在第i个数往右,(不包括第i个),有多少个数是小于num[i]的
dpR_max[i]:表示在第i个数往右,(不包括第i个),有多少个数是大于num[i]的
然后我们枚举每个num[i]作为d的值,就是作为num[d],因为有多少对num[a]<num[b],是可以预处理得到的。就是dpL_min[]的总和sum。枚举每个d值后,有多少个num[c]值呢?就是dpL_max[i]了。然后把这个数和sum相乘,就得到了一个结果。但是这个结果是偏多的。为什么呢?因为你的num[a]<num[b]中的num[a]是可能等于num[i](就是你当前枚举的d值)的。那么就是a==d,这个时候是选了3个元素,不瞒住条件,所以,就要把这些情况的可能的种数删除,就是ans -= dpL_max[i]*dpR_min[i]、意思就是,例如dpL_max[i],有多少个数能和num[i]结合是合法的num[c]>num[d]。dpR_min[i]有多少个数和num[i]就和是合法的num[a]<num[d]。这样,减去这个不合法的情况即可。那么有没可能是a==c && d==b呢?不可能,矛盾了,c>d a<b不符合。
还有三种情况是一样照做的。
这里要注意的还有数字是严格大于,在离散的时候注意一下就可以了
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; #include <iostream> #include <sstream> #include <vector> #include <set> #include <map> #include <queue> #include <string> int n; const int maxn = 50000 + 20; struct data { int val,pos; }book[maxn]; int a[maxn]; int c[maxn];//树状数组 int lowbit (int x)//得到x二进制末尾0的个数的2次方 2^num { return x&(-x); } void add (int pos,int val)//在第pos位加上val这个值 { while (pos<=n) //n是元素的个数 { c[pos] += val; pos += lowbit(pos); } return ; } int get_sum (int pos) //求解:1--pos的总和 { int ans = 0; while (pos) { ans += c[pos]; pos -= lowbit(pos); } return ans; } bool cmp (struct data a,struct data b) { return a.val < b.val; } LL get_inversion (int a[],int lena) { LL ans = 0;//逆序对一般都很多,需要用LL for (int i=1;i<=lena;++i)// a[]={5,2,1,4,3} ans=6 { add(a[i],1); ans += i-get_sum(a[i]); } return ans; } int dpL_min[maxn]; int dpL_max[maxn]; int dpR_min[maxn]; int dpR_max[maxn]; void init () { memset(c,0,sizeof c); memset(dpR_max,0,sizeof dpR_max); memset(dpR_min,0,sizeof dpR_min); memset(dpL_max,0,sizeof dpL_max); memset(dpL_min,0,sizeof dpL_min); } void work () { init(); for (int i=1;i<=n;++i) { scanf("%d",&book[i].val); book[i].pos = i; } sort(book+1,book+1+n,cmp); for (int i=1;i<=n;++i) { if (i>=2 && book[i].val == book[i-1].val) a[book[i].pos] = a[book[i-1].pos]; else a[book[i].pos]=i; //从小到大离散 } for (int i=1;i<=n;++i) { dpL_min[i] = get_sum(a[i]-1); dpL_max[i] = get_sum(n)-get_sum(a[i]); add(a[i],1); } memset(c,0,sizeof c); for (int i=n;i>=1;--i) { dpR_min[i] = get_sum(a[i]-1); dpR_max[i] = get_sum(n) - get_sum(a[i]); add(a[i],1); } // for (int i=1;i<=n;++i) // { // printf ("%d ",dpL_min[i]); // } // printf ("\n"); // // for (int i=1;i<=n;++i) // { // printf ("%d ",dpL_max[i]); // } // printf ("\n"); // // for (int i=1;i<=n;++i) // { // printf ("%d ",dpR_min[i]); // } // printf ("\n"); // // // for (int i=1;i<=n;++i) // { // printf ("%d ",dpR_max[i]); // } // printf ("\n"); LL sum = 0; for (int i=1;i<=n;++i) sum += dpL_min[i]; LL ans = 0; // cout<<sum<<endl; for (int i=1;i<=n;++i) { ans += dpL_max[i] * sum; ans -= 1LL*dpR_min[i]*dpR_max[i]; ans -= 1LL*dpL_max[i]*dpR_max[i]; ans -= 1LL*dpL_max[i]*dpL_min[i]; ans -= 1LL*dpR_min[i]*dpL_min[i]; } printf ("%I64d\n",ans); return ; } int main() { #ifdef local freopen("data.txt","r",stdin); #endif while(scanf("%d",&n)!=EOF && n) work(); return 0; }
HDU 5792 L - World is Exploding
标签:
原文地址:http://www.cnblogs.com/liuweimingcprogram/p/5778419.html