zoukankan      html  css  js  c++  java
  • Hdu 5213-Lucky 莫队,容斥原理,分块

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=5213

    Lucky

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


    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 Mquestions.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.The X 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
    5 3 1 2 1 2 3 1 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!
     
    Source
     
    Recommend
    hujie   |   We have carefully selected several similar problems for you:  5659 5658 5657 5656 5655 
     
    题意:给你一个a数列,再给出一些询问,每次询问给两个区间,分别为[l,r]和[u,v],且1<=l<=r<u<=v<=n,让你从[l,r]中找一个a[i],在[u,v]中找一个a[j],使得a[i]+a[j]=K,问有多少对。
    题解:
    好几天没发题解了。。。
    来个莫队压压惊。。。
    莫队+容斥
    莫队很好想的,主要是如何用容斥。
    我们把每组询问的两个区间写出来。
             l-----r--------u-----v
             |<A>|
                                |<B>|
                    |<--C-->|
    然后定义f(x,y)为第一个数i在x区间,第二个数j在y区间的a[i]+a[j]=K的方案数。
    我们要求的为f(A,B)=f(A+B+C,A+B+C)-f(A+C,A+C)-f(B+C,B+C)+f(C,C)
    然后就可以用莫队做了。
    这里有些小技巧:在加区间的时候,我们可以把区间的 两端点 和 当前区间的值是加还是减 记录下来,这样比较简单。
    另外这道题的数组大小好离奇。。。
    具体看程序:
     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define MAXN 30010
     4 #define MAXM 30010
     5 struct node
     6 {
     7     int l,r,id,fh;
     8 }q[MAXM*4];
     9 int a[MAXN],pos[MAXN],sum[MAXN*2],N,ans[MAXM*2];
    10 int read()
    11 {
    12     int s=0,fh=1;char ch=getchar();
    13     while(ch<'0'||ch>'9'){if(ch=='-')fh=-1;ch=getchar();}
    14     while(ch>='0'&&ch<='9'){s=s*10+(ch-'0');ch=getchar();}
    15     return s*fh;
    16 }
    17 void Add(int ll,int rr,int ii,int ff){q[++N].l=ll;q[N].r=rr;q[N].id=ii;q[N].fh=ff;}
    18 bool cmp(node aa,node bb)
    19 {
    20     if(pos[aa.l]==pos[bb.l])return aa.r<bb.r;
    21     return aa.l<bb.l;
    22 }
    23 int main()
    24 {
    25     int n,k,i,m,block,tot,L,R,U,V;
    26     while(scanf("%d",&n)!=EOF)
    27     {
    28         k=read();
    29         for(i=1;i<=n;i++)a[i]=read();
    30         m=read();
    31         N=0;
    32         for(i=1;i<=m;i++)
    33         {
    34             L=read();R=read();U=read();V=read();
    35             Add(L,V,i,1);Add(L,U-1,i,-1);Add(R+1,V,i,-1);Add(R+1,U-1,i,1);
    36         }
    37         block=(int)sqrt(n);
    38         for(i=1;i<=n;i++)pos[i]=(int)(i-1)/block+1;
    39         sort(q+1,q+N+1,cmp);
    40         memset(ans,0,sizeof(ans));
    41         L=1;R=0;
    42         tot=0;//当前区间有多少对a[i]+a[j]=k.
    43         memset(sum,0,sizeof(sum));//当前区间数字为i的有sum[i]个.
    44         for(i=1;i<=N;i++)
    45         {
    46             while(L<q[i].l)
    47             {
    48                 sum[a[L]]--;
    49                 tot-=sum[k-a[L]];
    50                 //sum[a[L]]--;
    51                 //if(k==a[L]*2)tot++;
    52                 L++;
    53             }
    54             while(L>q[i].l)
    55             {
    56                 L--;
    57                 tot+=sum[k-a[L]];
    58                 sum[a[L]]++;
    59             }
    60             while(R<q[i].r)
    61             {
    62                 R++;
    63                 tot+=sum[k-a[R]];
    64                 sum[a[R]]++;
    65             }
    66             while(R>q[i].r)
    67             {
    68                 sum[a[R]]--;
    69                 tot-=sum[k-a[R]];
    70                 //sum[a[R]]--;
    71                 //if(k==a[R]*2)tot++;
    72                 R--;
    73             }
    74             ans[q[i].id]+=q[i].fh*tot;
    75         }
    76         for(i=1;i<=m;i++)printf("%d
    ",ans[i]);
    77     }
    78     fclose(stdin);
    79     fclose(stdout);
    80     return 0;
    81 }
  • 相关阅读:
    实验四 (1):定义一个形状类(Shape)方法:计算周长,计算面积
    计算机结构的简化模型
    memcached性能测试之Twemperf
    Eclipse UML小工具AmaterasUML的配置和使用
    Kafka中文官方文档
    HBase Snapshot简介
    shell脚本学习系列之一---入门
    linux中shell变量$#,$@,$0,$1,$2的含义解释
    vim常用操作
    Linux多台主机间配置SSH免密登陆
  • 原文地址:https://www.cnblogs.com/Var123/p/5355909.html
Copyright © 2011-2022 走看看