hdu 5213 Lucky (莫队+容斥)

来源:互联网 发布:程序员之死女主角 编辑:程序博客网 时间:2024/05/29 16:28

Lucky

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1287    Accepted Submission(s): 461


Problem Description
WLD is always very lucky.His secret is a lucky number K.k is a fixed odd number. Now he meets a stranger with N numbers:a1,a2,...,aN.The stranger asks him M questions.Each question is like this:Given two ranges [Li,Ri] and [Ui,Vi],you can choose two numbers X and Y to make aX+aY=K.TheX you can choose is between Li and Ri and the Y you can choose is between Ui and Vi.How many pairs of numbers(X,Y) you can choose?
If WLD can answer all the questions correctly,he'll be the luckiest man in the world.Can you help him?
 

Input
There are multiple cases.(At MOST 5)

For each case:

The first line contains an integer
N(1N30000).

The following line contains an integer
K(2K2N),WLD's lucky number.K is odd.

The following line contains
N integers a1,a2,...,aN(1aiN).

The following line contains an integer
M(1M30000),the sum of the questions WLD has to answer.

The following
M lines,the i-th line contains 4 numbers Li,Ri,Ui,Vi(1LiRi<UiViN),describing the i-th question the stranger asks.
 

Output
For each case:

Print the total of pairs WLD can choose for each question.
 

Sample Input
53 1 2 1 2 31 1 2 3 5
 

Sample Output
2
Hint
a1+a4=a2+a3=3=K.So we have two pairs of numbers (1,4) and (2,3).Good luck!
 


题意:
有n个数 a1....an 并且还有一个k(奇数)
有m次询问,每一次询问在下标为[L,R]的a中取一个数aX,再在[U,V]中取一个数aY,使得aX+aY=k,且1<=L<R<U<V<=n
问你在上述区间中有多少对满足条件的X,Y

解析:


对于[L,R],[U,V]中的答案,可以分成[L,R],[R+1,U-1],[U,V]三段分别为①、②、③(如图)
①:表示每一个在①区间内取两个数使得和为k的对数(下面简称为对数),②、③同理
①②:表示从①里面取一个,从②里面取一个的对数
那么[L,V]中区间的对数f(L,V)=①+②+③+①②+②③+①③
f(L,U-1)=①+②+①②
f(R+1,V)=③+②+③②
f(R+1,U-1)=②
那么我们所求的就是③=f(L,V)-f(L,U-1)-f(R+1,V)+f(R+1,U-1)

这就是这道题所需要用到的容斥定理
莫队分块的就是把一次询问分成了四个独立的区间,然后分块之后,按块排序,之后进行区间移动,求出每一个分出来的区间的答案就可以了
#include<cstdio>#include<cstring>#include<cstdlib>#include<cmath>#include<algorithm>using namespace std;const int MAXN = 30000+10;typedef long long int ll;typedef struct node{    int l;    int r;    int id;    ll ans;}node;node query[MAXN *4];int n,k,m,cnt;int a[MAXN];int part[MAXN];ll time[MAXN*2],ans;bool cmp1(node a,node b){    if(part[a.l]==part[b.l]) return a.r<b.r;    return a.l<b.l;}bool cmp2(node a,node b){   return a.id<b.id;}void update(int x,int inc){    if(k-x>=1&&k-x<=n) //!    {        ans=ans-time[x]*time[k-x];        time[x]+=inc;        ans=ans+time[x]*time[k-x];    }}void Mo(){    int block=sqrt(n);    for(int i=1;i<=n;i++)    {        part[i]=(i-1)/block;    }    sort(query,query+4*m,cmp1);    int l=1;int r=0;    ans=0;    for(int i=0;i<4*m;i++)    {        if(query[i].l>query[i].r)        {            query[i].ans=0;            continue;        }        while(l<query[i].l) update(a[l],-1),l++;        while(l>query[i].l) update(a[l-1],1),l--;        while(r<query[i].r) update(a[r+1],1),r++;        while(r>query[i].r) update(a[r],-1),r--;        query[i].ans=ans;    }}int main(){    while(scanf("%d",&n)!=EOF)    {        memset(time,0,sizeof(time));        scanf("%d",&k);        for(int i=1;i<=n;i++)        {            scanf("%d",&a[i]);        }        scanf("%d",&m);        int l1,r1,l2,r2;        cnt=0;        for(int i=0;i<m;i++)        {            scanf("%d%d%d%d",&l1,&r1,&l2,&r2);            query[cnt].id=cnt;            query[cnt].l=l1;            query[cnt++].r=r2;            query[cnt].id=cnt;            query[cnt].l=l1;            query[cnt++].r=l2-1;            query[cnt].id=cnt;            query[cnt].l=r1+1;            query[cnt++].r=r2;            query[cnt].id=cnt;            query[cnt].l=r1+1;            query[cnt++].r=l2-1;        }        Mo();        sort(query,query+4*m,cmp2);        for(int i=0;i<4*m;i=i+4)        {            ll res=query[i].ans-query[i+1].ans-query[i+2].ans+query[i+3].ans;            printf("%lld\n",res);        }    }    return 0;}