zoukankan      html  css  js  c++  java
  • [BZOJ4836]二元运算(分治FFT)

    4836: [Lydsy1704月赛]二元运算

    Time Limit: 8 Sec  Memory Limit: 128 MB
    Submit: 578  Solved: 202
    [Submit][Status][Discuss]

    Description

    定义二元运算 opt 满足
    现在给定一个长为 n 的数列 a 和一个长为 m 的数列 b ,接下来有 q 次询问。每次询问给定一个数字 c 
    你需要求出有多少对 (i, j) 使得 a_i  opt b_j=c 。

    Input

    第一行是一个整数 T (1≤T≤10) ,表示测试数据的组数。
    对于每组测试数据:
    第一行是三个整数 n,m,q (1≤n,m,q≤50000) 。
    第二行是 n 个整数,表示 a_1,a_2,?,a_n (0≤a_1,a_2,?,a_n≤50000) 。
    第三行是 m 个整数,表示 b_1,b_2,?,b_m (0≤b_1,b_2,?,b_m≤50000) 。
    第四行是 q 个整数,第 i 个整数 c_i (0≤c_i≤100000) 表示第 i 次查询的数。

    Output

    对于每次查询,输出一行,包含一个整数,表示满足条件的 (i, j) 对的个数。

    Sample Input

    2
    2 1 5
    1 3
    2
    1 2 3 4 5
    2 2 5
    1 3
    2 4
    1 2 3 4 5

    Sample Output

    1
    0
    1
    0
    0
    1
    0
    1
    0
    1

    HINT

    Source

    [Submit][Status][Discuss]

    挺有意思的一道题,应该不难想到是分治FFT,主要是CDQ分治函数内部要想得很清楚。

    首先如果只有加法,就是裸卷积。

    如果只有减法,那么有$c_k=sumlimits_{i=k}^na_ib_{i-k}$,把b翻转,最后将c前移n位即可$c_{n+k}=sumlimits_{i=0}^na_{k+i}b_{n-i}$

    现在有了大小关系的限制,我们可以通过$CDQ$分治处理。

    首先特判掉相等的情况,然后对于$[l,r]$这个区间,将$[l,mid]$和$[mid+1,r]$递归处理,现在问题只剩下$a[l,mid]$和$b[mid+1,r]$,$a[mid+1,r]$和$b[l,mid]$两个问题了。

    显然前一个问题直接将$a$前移$l$位,$b$前移$mid+1$位,卷起来之后再后移$l+mid+1$位即可。后一个问题,将$a$前移$mid+1$位,b翻转后前移$l$位,这样卷之后的区间下标是从$0$开始的,而我们的差是从$1$开始的,所以右移$1$位。

    卷的时候还是一定要注意次数界!NTT也可以。

     1 #include<cmath>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define mem(a) memset(a,0,sizeof(a))
     6 typedef long long ll;
     7 using namespace std;
     8 
     9 const int N=500010;
    10 const double pi=acos(-1.);
    11 struct C{ double x,y; }A[N],B[N];
    12 int a[N],b[N],rev[N],n,T,x,m,Q,mx,len1,len2;
    13 ll ans[N];
    14 
    15 C operator +(C &a,C &b){ return (C){a.x+b.x,a.y+b.y}; }
    16 C operator -(C &a,C &b){ return (C){a.x-b.x,a.y-b.y}; }
    17 C operator *(const C &a,const C &b){ return (C){a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x}; }
    18 
    19 void DFT(C a[],int n,int f){
    20     for (int i=0; i<n; i++) if (i<rev[i]) swap(a[i],a[rev[i]]);
    21     for (int i=1; i<n; i<<=1){
    22         C wn=(C){cos(pi/i),f*sin(pi/i)};
    23         for (int p=i<<1,j=0; j<n; j+=p){
    24             C w=(C){1,0};
    25             for (int k=0; k<i; k++,w=w*wn){
    26                 C x=a[j+k],y=w*a[i+j+k]; a[j+k]=x+y; a[i+j+k]=x-y;
    27             }
    28         }
    29     }
    30     if (f==1) return;
    31     for (int i=0; i<n; i++) a[i].x/=n;
    32 }
    33 
    34 void CDQ(int l,int r){
    35     if (l==r) return;
    36     int mid=(l+r)>>1,n,L=0;
    37     for (n=1; n<=r-l+1; n<<=1) L++;
    38     for (int i=0; i<n; i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1));
    39     
    40     for (int i=0; i<n; i++) A[i]=B[i]=(C){0,0};
    41     for (int i=l; i<=mid; i++) A[i-l].x=a[i];
    42     for (int i=mid+1; i<=r; i++) B[i-mid-1].x=b[i];
    43     DFT(A,n,1); DFT(B,n,1);
    44     for (int i=0; i<n; i++) A[i]=A[i]*B[i];
    45     DFT(A,n,-1);
    46     for (int i=0; i<n; i++) ans[i+mid+1+l]+=(ll)(A[i].x+0.5);
    47     
    48     for (int i=0; i<n; i++) A[i]=B[i]=(C){0,0};
    49     for (int i=mid+1; i<=r; i++) A[i-mid-1].x=a[i];
    50     for (int i=l; i<=mid; i++) B[mid-i].x=b[i];
    51     DFT(A,n,1); DFT(B,n,1);
    52     for (int i=0; i<n; i++) A[i]=A[i]*B[i];
    53     DFT(A,n,-1);
    54     for (int i=0; i<n; i++) ans[i+1]+=(ll)(A[i].x+0.5);
    55     CDQ(l,mid); CDQ(mid+1,r);
    56 }
    57 
    58 int main(){
    59     freopen("bzoj4836.in","r",stdin);
    60     freopen("bzoj4836.out","w",stdout);
    61     for (scanf("%d",&T); T--; ){
    62         scanf("%d%d%d",&n,&m,&Q); mem(ans); mem(a); mem(b); len1=len2=0;
    63         for (int i=1; i<=n; i++) scanf("%d",&x),a[x]++,len1=max(len1,x);
    64         for (int i=1; i<=m; i++) scanf("%d",&x),b[x]++,len2=max(len2,x);
    65         for (int i=1; i<=len1 && i<=len2; i++) ans[0]+=1ll*a[i]*b[i];
    66         CDQ(0,max(len1,len2));
    67         for (int i=1; i<=Q; i++) scanf("%d",&x),printf("%lld
    ",ans[x]);
    68     }
    69     return 0;
    70 }
  • 相关阅读:
    《让未来的你,感谢现在的自己》——自己努力
    老罗——《我的奋斗》
    1. opencv的初体验
    opencv初体验
    opencv的初体验
    python学习2——数据类型
    卷积的意义
    C#学习笔记一
    C++知识点
    二维数组作为参数传递
  • 原文地址:https://www.cnblogs.com/HocRiser/p/8689935.html
Copyright © 2011-2022 走看看