3509: [CodeChef] COUNTARI

Time Limit: 40 Sec  Memory Limit: 128 MB
Submit: 883  Solved: 250
[Submit][Status][Discuss]

Description

给定一个长度为N的数组A[],求有多少对i, j, k(1<=i<j<k<=N)满足A[k]-A[j]=A[j]-A[i]。

Input

第一行一个整数N(N<=10^5)。
接下来一行N个数A[i](A[i]<=30000)。

Output

一行一个整数。

Sample Input

10
3 5 3 6 3 4 10 4 5 2

Sample Output

9

HINT

Source

分析:

考虑枚举中间项$a[j]$,我们可以使用$FFT$快速计算$ik$的配对个数,但是这样显然是$O(Nmaxnumlgmaxnum)$的,还没有暴力跑的快...

所以可以考虑分块,对于$ijk$都在同一块内或者$ij$在一块或者$jk$在一块的情况我们预处理出来,这些的复杂度是$O(len*N)$的,然后$ik$位于和$j$不同快的情况我们用$FFT$来计算,这个的复杂度是$O(\frac {N}{len}*maxnumlgmaxnum)$的...

如此计算,块的大小大概开到3000~2000就可以过去了...

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std; const int maxn=100000+5,maxblock=50+5;
const double pi=acos(-1); int n,N,m,L,blo,a[maxn],R[maxn],id[maxn],be[maxblock],en[maxblock],cnt[maxblock][maxn];
long long ans; struct complex{ double r,i; inline complex(double a=0,double b=0): r(a),i(b) {}; inline complex operator + (const complex &a){
return complex(r+a.r,i+a.i);
} inline complex operator - (const complex &a){
return complex(r-a.r,i-a.i);
} inline complex operator * (const complex &a){
return complex(r*a.r-i*a.i,r*a.i+i*a.r);
} }l[maxn],s[maxn]; inline void FFT(complex *l,int f){
for(int i=0;i<N;i++)
if(i>R[i]) swap(l[i],l[R[i]]);
for(int i=1;i<N;i<<=1){
complex wn(cos(pi/i),f*sin(pi/i));
for(int j=0;j<N;j+=i<<1){
complex w(1,0);
for(int k=0;k<i;k++,w=w*wn){
complex x=l[j+k],y=l[j+k+i]*w;
l[j+k]=x+y;
l[j+k+i]=x-y;
}
}
}
if(f==-1)
for(int i=0;i<N;i++)
l[i].r/=N;
} signed main(void){
// freopen("countari.in","r",stdin);
// freopen("countari.out","w",stdout);
scanf("%d",&n);
L=0;ans=0;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(N=1;N<=60000;N<<=1) L++;
for(int i=0;i<N;i++)
R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
blo=min(int(sqrt(n)*10),n);
for(int i=1;i<=n;i++) id[i]=(i-1)/blo+1;
for(int i=1;i<=id[n];i++)
be[i]=lower_bound(id+1,id+n+1,i)-id,
en[i]=upper_bound(id+1,id+n+1,i)-id-1;
memset(cnt,0,sizeof(cnt));
for(int i=1;i<=n;i++) cnt[id[i]][a[i]]++;
for(int B=1;B<=id[n];B++){
for(int i=be[B];i<=en[B];i++){
cnt[B][a[i]]--;
for(int j=be[B];j<i;j++)
if(2*a[i]-a[j]>=0) ans+=cnt[B][2*a[i]-a[j]];
}
}
memset(cnt,0,sizeof(cnt));
for(int i=1;i<=n;i++) cnt[0][a[i]]++;
for(int B=1;B<=id[n];B++){
for(int i=be[B];i<=en[B];i++) cnt[0][a[i]]--;
for(int i=be[B];i<=en[B];i++){
for(int j=be[B];j<i;j++)
if(2*a[i]-a[j]>=0) ans+=cnt[0][2*a[i]-a[j]];
}
}
memset(cnt,0,sizeof(cnt));
for(int i=1;i<=n;i++) cnt[0][a[i]]++;
for(int B=id[n];B>=1;B--){
for(int i=be[B];i<=en[B];i++) cnt[0][a[i]]--;
for(int i=be[B];i<=en[B];i++){
for(int j=i-1;j>=be[B];j--)
if(2*a[j]-a[i]>=0) ans+=cnt[0][2*a[j]-a[i]];
}
}
for(int B=1;B<=id[n];B++){
for(int i=0;i<N;i++) l[i].r=l[i].i=s[i].r=s[i].i=0;
for(int i=1;i<be[B];i++) l[a[i]].r++;
for(int i=en[B]+1;i<=n;i++) s[a[i]].r++;
FFT(l,1);FFT(s,1);
for(int i=0;i<N;i++) l[i]=l[i]*s[i];
FFT(l,-1);
for(int i=be[B];i<=en[B];i++) ans+=int(l[a[i]*2].r+0.5);
}
printf("%lld\n",ans);
return 0;
}

  


By NeighThorn

BZOJ 3509: [CodeChef] COUNTARI的更多相关文章

  1. [BZOJ 3509] [CodeChef] COUNTARI (FFT+分块)

    [BZOJ 3509] [CodeChef] COUNTARI (FFT+分块) 题面 给出一个长度为n的数组,问有多少三元组\((i,j,k)\)满足\(i<j<k,a_j-a_i=a_ ...

  2. bzoj 3509: [CodeChef] COUNTARI] [分块 生成函数]

    3509: [CodeChef] COUNTARI 题意:统计满足\(i<j<k, 2*a[j] = a[i] + a[k]\)的个数 \(2*a[j]\)不太好处理,暴力fft不如直接暴 ...

  3. BZOJ 3509 [CodeChef] COUNTARI ——分块 FFT

    分块大法好. 块内暴力,块外FFT. 弃疗了,抄SX队长$silvernebula$的代码 #include <map> #include <cmath> #include & ...

  4. BZOJ3509: [CodeChef] COUNTARI

    3509: [CodeChef] COUNTARI Time Limit: 40 Sec  Memory Limit: 128 MBSubmit: 339  Solved: 85[Submit][St ...

  5. bzoj 4546: codechef XRQRS [可持久化Trie]

    4546: codechef XRQRS 可持久化Trie codechef上过了,bzoj上蜜汁re,看别人说要开5.2e5才行. #include <iostream> #includ ...

  6. BZOJ 3221: [Codechef FEB13] Obserbing the tree树上询问( 可持久化线段树 + 树链剖分 )

    树链剖分+可持久化线段树....这个一眼可以看出来, 因为可持久化所以写了标记永久化(否则就是区间修改的线段树的持久化..不会), 结果就写挂了, T得飞起...和管理员拿数据调后才发现= = 做法: ...

  7. BZOJ 3514: Codechef MARCH14 GERALD07加强版( LCT + 主席树 )

    从左到右加边, 假如+的边e形成环, 那么记下这个环上最早加入的边_e, 当且仅当询问区间的左端点> _e加入的时间, e对答案有贡献(脑补一下). 然后一开始是N个连通块, 假如有x条边有贡献 ...

  8. BZOJ 4260: Codechef REBXOR( trie )

    求出前缀和, 那么以第x个元素结尾的最大异或值是max(sumx^sump)(1≤p<x), 用trie加速. 后缀同理, 然后扫一遍就OK了.时间复杂度O(31N) ------------- ...

  9. BZOJ 3514: Codechef MARCH14 GERALD07加强版 [LCT 主席树 kruskal]

    3514: Codechef MARCH14 GERALD07加强版 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 1312  Solved: 501 ...

随机推荐

  1. es6展开运算符

    数组的展开合并 现在有两个数组[1, 2, 3, 4]和[5, 6, 7],想要将两个函数拼接成一个新的函数. //es5的写法 let arr1 = [1, 2, 3, 4]; let arr2 = ...

  2. C/C++程序基础 (七)继承和多态

    多态 编译时多态:重载 运行时多态:虚函数.根据运行时的类别获取正确的虚指针,从而定位正确的虚函数. 虚函数 虚函数指针:指向虚函数表.多重继承则含有多个基类的虚函数指针. 虚函数表:函数指针集合.普 ...

  3. linux关于权限

    用户权限:drwxr-x---. 8 root root 4096 8月 6 23:18 mnt 第一个root:所有者 即root用户第二个root:所有者所在的组mnt:所有者创建的文件夹Rwx: ...

  4. 【转】Mysql查询语句优化策略

    1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索 ...

  5. Tufurama CodeForces - 961E

    Tufurama CodeForces - 961E 题意:有一部电视剧有n季,每一季有ai集.问有多少对i,j存在第i季第j集也同时存在第j季第i集. 思路:核心问题还是统计对于第i季,你要统计第i ...

  6. 第 8 章: 模块, 包与分发---Word

    第八章: 模块, 包 与 分发 描述: 大型Python程序以模块和包的形式组织.另外,Python标准库中包含大量模块.本章详细介绍模块和包系统.还将提供有关如何安装第三方模块和分发源代码的信息. ...

  7. Java的多态性Polymorphism

    原文地址:http://www.cnblogs.com/jack204/archive/2012/10/29/2745150.html Java中多态性的实现 什么是多态 面向对象的三大特性:封装.继 ...

  8. Android 服务入门

    前言:硬着头皮把数据库SQLite看完了,接下来就是android服务了,因为自己本身就是菜鸟,所以呢,也只是做做笔记,技术上的东西就别指望我了. 1.什么是服务呢?举个例子,百度地图,美团外卖,OF ...

  9. P3386 【模板】二分图匹配(匈牙利&最大流)

    P3386 [模板]二分图匹配 题目背景 二分图 题目描述 给定一个二分图,结点个数分别为n,m,边数为e,求二分图最大匹配数 输入输出格式 输入格式: 第一行,n,m,e 第二至e+1行,每行两个正 ...

  10. 使用code::blocks编译windows的dll链接库

    因为机子上没有安装Visual Studio,所以找到了一种通过code::blocks编译dll的方式,踩到的坑是code::blocks默认的compiler是32位的,这样编译出的dll也是32 ...