1145: [CTSC2008]图腾totem
Description
在完成了古越州圆盘密码的研究之后,考古学家小布来到了南美大陆的西部。相传很久以前在这片土地上生活着两个部落,一个部落崇拜闪电,另一个部落崇拜高山,他们分别用闪电和山峰的形状作为各自部落的图腾。小布的团队在山洞里发现了一幅巨大的壁画,壁画上被标记出了N个点,经测量发现这N个点的水平位置和竖直位置是两
两不同的。小布认为这幅壁画所包含的信息仅与这N个点的相对位置有关,因此不妨设坐标分别为(1, y1) , (2, y2), …, (n, yn),其中y1~yn是1~N的一个排列。小布的团队打算研究在这幅壁画中包含着多少个图腾,其中闪电图腾的定义图示如下(图腾的形式只与4个纵坐标值的相对大小排列顺序有关):
崇拜高山的部落有两个氏族,因而山峰图腾有如下两种形式,左边为A类,右边为B类(同样,图腾的形式也都只与4个纵坐标值的大小排列顺序有关):
小布的团队希望知道,这N个点中两个部落图腾数目的差值。因此在本题中,你需要帮助小布的团队编写一个程序,计算闪电图腾数目减去山峰图腾数目的值,由于该值可能绝对值较大,本题中只需输出该值对16777216的余数(注意余数必为正值,例如-1对16777216的余数为16777215)。
Input
第一行包含一个整数N,为点的数目。接下来一行包含N个整数,分别为y1, y2, …, yn。保证y1, y2, …, yn是1~N的一个排列。N ≤ 200000
Output
仅包含一个数,表示闪电图腾数目与山峰图腾数目的差值对16777216的余数。
Sample Input
【样例输入一】
5
1 5 3 2 4
【样例输入二】
4
1 2 4 3
Sample Output
【样例输出一】
0
【样例输出二】
16777215
【解题报告】
显然题目要求的是
1324-1432-1243=(1*2*-1423)-(14**-1423)-(12**-1234)
=1*2*-14**-12**+1234
=1*2*-(1***-13**)+1234
=1*2*-1***+13**+1234
所以我们只要求出来1x2x,1xxx,13xx,1234的方案数就好了。
我们首先预处理出每个数他左边比他小的有多少右边比他小的数有多少.记为l[i],r[i];
对于1xxx;
我们枚举1,显然1右边的数都比1大,那么就是从(n-i-r[i])中选3个数。
对于1234;
我们枚举3,
显然3右边的数比3大.方案数为(n-i-r[i]);
3左边的数都比他小,并且需要递减.
所以方案数就是sigma(l[x])(x < i,a[x] < a[i]);
这个东西显然可以用树状数组处理。
对于1x2x;
我们枚举2.
显然2右边的数都比2大,这样的数有(n-i-r[i])个。
2左边的数一个比2大一个比2小。
这个东西直接算不好算,我们考虑补集转换。
我们先把固定1,显然这样的方案数有l[i]*(i-1)个。
这样肯定多算了.
我们先减去两个数都比2小并且1在左边的方案数.即l[i]*(l[i]-1)/2;
我们还要减去1在右边的情况
这样显然是sigma(x)(a[x] < a[i],x < i);这个东西当然也可以用树状数组处理。
对于13xx
我们枚举3.
显然在3的右边有一个4,4的方案数显然是(n-i-r[i]);
我们还是考虑补集转换。
我们先固定2,1一定比2小,那么总方案数为sigma(a[x])(a[x] < a[i],x > i);
它也可以用树状数组处理。
这样多算了很多。
我们减去两个数都在右边的情况,即减去r[i]*(r[i]+1)/2;
来自:http://blog.csdn.net/sunshinezff/article/details/48286769
代码如下:
/**************************************************************
Problem: 1145
User: onepointo
Language: C++
Result: Accepted
Time:1240 ms
Memory:6760 kb
****************************************************************/
#include<cstring>
#include<iostream>
#include<cstdio>
using namespace std;
#define N 200010
#define p 16777216
#define lowbit(x) (x&-x)
long long c[N],l[N],r[N];
int h[N],n,t1,t2,t3,t4;
void updata(int x,int v)
{
for(int i=x;i<=n;i+=lowbit(i)) c[i]+=v;
}
long long query(int x)
{
long long ans(0);
for(int i=x;i;i-=lowbit(i)) ans+=c[i];
return ans;
}
int work1()//1x2x
{
memset(c,0,sizeof(c));
long long ans(0);
for(int i=1;i<=n;i++)
{
(ans+=(l[i]*(i-1)-l[i]*(l[i]-1)/2-query(h[i]))*(n-r[i]-i))%=p;
updata(h[i],i);
}
return ans;
}
int work2()//1234
{
memset(c,0,sizeof(c));
long long ans(0);
for(int i=1;i<=n;i++)
{
(ans+=query(h[i])*(n-i-r[i]))%=p;
updata(h[i],l[i]);
}
return ans;
}
int work3()//13xx
{
memset(c,0,sizeof(c));
long long ans(0);
for(int i=n;i;i--)
{
(ans+=(query(h[i])-r[i]*(r[i]+1)/2)*(n-r[i]-i))%=p;
updata(h[i],h[i]);
}
return ans;
}
int work4()//1xxx
{
long long ans(0);
for(int i=1;i<=n;i++)
{
long long temp=n-i-r[i];
if(temp>=3) (ans+=temp*(temp-1)*(temp-2)/6)%=p;
}
return ans;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%d",&h[i]);
l[i]=query(h[i]);
r[i]=h[i]-1-l[i];
updata(h[i],1);
}
memset(c,sizeof(c),0);
t1=work1();t2=work2();t3=work3();t4=work4();
printf("%d",(t1+t2+t3-t4+p)%p);
return 0;
}