• bzoj4836 [Lydsy2017年4月月赛]二元运算


    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

    正解:分治$FFT$。

    比较简单的一个题。

    构造$a,b$的生成函数,$a[i]$表示$a$序列中$i$出现的次数。

    考虑分治,我们每次把区间分成两半时,跑两次$FFT$。

    对于第一种情况,我们直接把$a$的$[l,mid]$部分和$b$的$[mid+1,r]$卷积即可。

    对于第二种情况,我们考虑把$b$序列的$[l,mid]$部分翻转,那么就是$a$的$[mid+1,r]$部分和翻转以后的$b$的$[l,mid]$部分卷积得到的多项式。

    然后我们递归两个子区间就行了。

    还有两个序列中元素相等的情况,直接特判就行了。

     1 #include <bits/stdc++.h>
     2 #define il inline
     3 #define RG register
     4 #define ll long long
     5 #define N (500010)
     6 
     7 using namespace std;
     8 
     9 struct data{ double x,y; }A[N],B[N];
    10 
    11 const double pi=acos(-1.0);
    12 int a[N],b[N],rev[N],n,m,q,Mx,len1,len2;
    13 ll ans[N];
    14 
    15 il int gi(){
    16   RG int x=0,q=1; RG char ch=getchar();
    17   while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
    18   if (ch=='-') q=-1,ch=getchar();
    19   while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar();
    20   return q*x;
    21 }
    22 
    23 il data operator + (const data &a,const data &b){
    24   return (data){a.x+b.x,a.y+b.y};
    25 }
    26 
    27 il data operator - (const data &a,const data &b){
    28   return (data){a.x-b.x,a.y-b.y};
    29 }
    30 
    31 il data operator * (const data &a,const data &b){
    32   return (data){a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x};
    33 }
    34 
    35 il void fft(data *a,RG int n,RG int f){
    36   for (RG int i=0;i<n;++i) if (i<rev[i]) swap(a[i],a[rev[i]]);
    37   for (RG int i=1;i<n;i<<=1){
    38     RG data wn=(data){cos(pi/i),sin(pi/i)},x,y;
    39     for (RG int j=0;j<n;j+=i<<1){
    40       RG data w=(data){1,0};
    41       for (RG int k=0;k<i;++k,w=w*wn){
    42     x=a[j+k],y=w*a[j+k+i];
    43     a[j+k]=x+y,a[j+k+i]=x-y;
    44       }
    45     }
    46   }
    47   if (f==1) return; reverse(a+1,a+n);
    48   for (RG int i=0;i<n;++i) a[i].x/=n; return;
    49 }
    50 
    51 il void solve(RG int l,RG int r){
    52   if (l==r) return; RG int mid=(l+r)>>1,len,lg=0;
    53   for (len=1;len<=r-l+1;len<<=1) ++lg;
    54   for (RG int i=0;i<len;++i) rev[i]=rev[i>>1]>>1|((i&1)<<(lg-1));
    55   for (RG int i=0;i<len;++i) A[i]=B[i]=(data){0,0};  
    56   for (RG int i=l;i<=mid;++i) A[i-l].x=a[i]; fft(A,len,1);
    57   for (RG int i=mid+1;i<=r;++i) B[i-mid-1].x=b[i]; fft(B,len,1);
    58   for (RG int i=0;i<len;++i) A[i]=A[i]*B[i]; fft(A,len,-1);
    59   for (RG int i=0;i<len;++i) ans[i+mid+1+l]+=(ll)(A[i].x+0.5);
    60   for (RG int i=0;i<len;++i) A[i]=B[i]=(data){0,0};
    61   for (RG int i=mid+1;i<=r;++i) A[i-mid-1].x=a[i]; fft(A,len,1);
    62   for (RG int i=l;i<=mid;++i) B[mid-i].x=b[i]; fft(B,len,1);
    63   for (RG int i=0;i<len;++i) A[i]=A[i]*B[i]; fft(A,len,-1);
    64   for (RG int i=0;i<len;++i) ans[i+1]+=(ll)(A[i].x+0.5);
    65   solve(l,mid),solve(mid+1,r); return;
    66 }
    67 
    68 il void work(){
    69   n=gi(),m=gi(),q=gi(),memset(ans,0,sizeof(ans));
    70   memset(a,0,sizeof(a)),memset(b,0,sizeof(b)),len1=len2=0;
    71   for (RG int i=1,x;i<=n;++i) ++a[x=gi()],len1=max(len1,x);
    72   for (RG int i=1,x;i<=m;++i) ++b[x=gi()],len2=max(len2,x);
    73   for (RG int i=1;i<=len1 && i<=len2;++i) ans[0]+=1LL*a[i]*b[i];
    74   Mx=max(len1,len2),solve(0,Mx);
    75   for (RG int i=1;i<=q;++i) printf("%lld
    ",ans[gi()]); return;
    76 }
    77 
    78 int main(){
    79 #ifndef ONLINE_JUDGE
    80   freopen("calc.in","r",stdin);
    81   freopen("calc.out","w",stdout);
    82 #endif
    83   RG int T=gi();
    84   while (T--) work();
    85   return 0;
    86 }
  • 相关阅读:
    不要对春运抱有幻想
    初识HTTP消息头(一)
    java中ArrayList 、LinkList区别以及速度对比
    jar包和war包的区别
    LUA 日期处理
    NGINXLUA——变量浅谈
    JDK和JRE的区别
    理解HTTP消息头 (五)——使用multipart/formdata上传文件
    安装Jetty
    TOMCATJARWAR事例讲解
  • 原文地址:https://www.cnblogs.com/wfj2048/p/7418814.html
Copyright © 2020-2023  润新知