CodeChef COUNTARI Arithmetic Progressions(分块 + FFT)
题目
Source
http://vjudge.net/problem/142058
Description
Given N integers A1, A2, …. AN, Dexter wants to know how many ways he can choose three numbers such that they are three consecutive terms of an arithmetic progression.
Meaning that, how many triplets (i, j, k) are there such that 1 ≤ i < j < k ≤ N and Aj - Ai = Ak - Aj.
So the triplets (2, 5, 8), (10, 8, 6), (3, 3, 3) are valid as they are three consecutive terms of an arithmetic
progression. But the triplets (2, 5, 7), (10, 6, 8) are not.
Input
First line of the input contains an integer N (3 ≤ N ≤ 100000). Then the following line contains N space separated integers A1, A2, …, AN and they have values between 1 and 30000 (inclusive).
Output
Output the number of ways to choose a triplet such that they are three consecutive terms of an arithmetic progression.
Sample Input
10
3 5 3 6 3 4 10 4 5 2
Sample Output
9
分析
题目大概说给一个长N的序列A,问有多少个三元组<i,j,k>满足i<j<k且Ai+Ak=2Aj。
i<j<k这个关系不好搞,正解好像是分块:
- 把序列分解成若干块,每一块长度大约为B。分三种情况考虑:
- 对于三个都在同一块的:枚举各个块,然后通过枚举i和k并更新记录j的信息求出对数。时间复杂度$O(N/B\times B\times B)=O(NB)$。
- 对于只有两个在同一块的:枚举各个块,并更新记录前面所有块和后面所有块的信息,然后枚举块内的两个数,另一个数可能在块前也可能在块后,这样求出对数。时间复杂度$O(N/B\times B\times B)=O(NB)$。
- 对于三个数都在不同块的:枚举各个块,并更新记录前面所有块和后面所有块的信息,然后构造多项式用FFT求出前后两边组合成各个和的方案数,通过枚举块内的j即可求出对数。时间复杂度$O(N/B\times 65535\times 16+N/B\times B)$
- 然后就是B大小的设定,我设定的是$5\sqrt N$。
- 最后我连枚举都不会枚举。。还有有个地方只考虑是否大于0,没考虑是否小于等于30000,数组越界,WA了好久。。
代码
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define INF (1<<30)
#define MAXN 66666
const double PI=acos(-1.0); struct Complex{
double real,imag;
Complex(double _real,double _imag):real(_real),imag(_imag){}
Complex(){}
Complex operator+(const Complex &cp) const{
return Complex(real+cp.real,imag+cp.imag);
}
Complex operator-(const Complex &cp) const{
return Complex(real-cp.real,imag-cp.imag);
}
Complex operator*(const Complex &cp) const{
return Complex(real*cp.real-imag*cp.imag,real*cp.imag+cp.real*imag);
}
void setValue(double _real=0,double _imag=0){
real=_real; imag=_imag;
}
}; int len;
Complex wn[MAXN],wn_anti[MAXN]; void FFT(Complex y[],int op){
for(int i=1,j=len>>1,k; i<len-1; ++i){
if(i<j) swap(y[i],y[j]);
k=len>>1;
while(j>=k){
j-=k;
k>>=1;
}
if(j<k) j+=k;
}
for(int h=2; h<=len; h<<=1){
Complex Wn=(op==1?wn[h]:wn_anti[h]);
for(int i=0; i<len; i+=h){
Complex W(1,0);
for(int j=i; j<i+(h>>1); ++j){
Complex u=y[j],t=W*y[j+(h>>1)];
y[j]=u+t;
y[j+(h>>1)]=u-t;
W=W*Wn;
}
}
}
if(op==-1){
for(int i=0; i<len; ++i) y[i].real/=len;
}
}
void Convolution(Complex A[],Complex B[],int n){
for(len=1; len<(n<<1); len<<=1);
for(int i=n; i<len; ++i){
A[i].setValue();
B[i].setValue();
} FFT(A,1); FFT(B,1);
for(int i=0; i<len; ++i){
A[i]=A[i]*B[i];
}
FFT(A,-1);
} int a[111111];
int cnt[33100],cnt0[33100],cnt1[33100];
Complex A[MAXN],B[MAXN]; int main(){
for(int i=0; i<MAXN; ++i){
wn[i].setValue(cos(2.0*PI/i),sin(2.0*PI/i));
wn_anti[i].setValue(wn[i].real,-wn[i].imag);
}
int n;
while(~scanf("%d",&n)){
for(int i=0; i<n; ++i){
scanf("%d",a+i);
}
int block=(int)(sqrt(n)+1e-6)*5; long long ans=0; for(int b=0; b<n; b+=block){
for(int i=0; i<block && b+i<n; ++i){
for(int j=i+1; j<block && b+j<n; ++j){
int tmp=a[b+i]+a[b+j];
if((tmp&1)==0){
ans+=cnt[tmp>>1];
}
++cnt[a[b+j]];
}
for(int j=i+1; j<block && b+j<n; ++j){
--cnt[a[b+j]];
}
}
} memset(cnt0,0,sizeof(cnt0));
memset(cnt1,0,sizeof(cnt1));
for(int i=0; i<n; ++i){
++cnt1[a[i]];
}
for(int b=0; b<n; b+=block){
for(int i=0; i<block && b+i<n; ++i){
--cnt1[a[b+i]];
}
for(int i=0; i<block && b+i<n; ++i){
for(int j=i+1; j<block && b+j<n; ++j){
int tmp=a[b+i]*2-a[b+j];
if(tmp>0 && tmp<=30000) ans+=cnt0[tmp];
tmp=a[b+j]*2-a[b+i];
if(tmp>0 && tmp<=30000) ans+=cnt1[tmp];
}
}
for(int i=0; i<block && b+i<n; ++i){
++cnt0[a[b+i]];
}
} memset(cnt0,0,sizeof(cnt0));
memset(cnt1,0,sizeof(cnt1));
for(int i=0; i<n; ++i){
++cnt1[a[i]];
}
for(int b=0; b<n; b+=block){
for(int i=0; i<block && b+i<n; ++i){
--cnt1[a[b+i]];
} for(int i=0; i<=30000; ++i){
A[i].setValue(cnt0[i]);
B[i].setValue(cnt1[i]);
}
Convolution(A,B,30001);
for(int i=0; i<block && b+i<n; ++i){
ans+=(long long)(A[a[b+i]<<1].real+0.5);
} for(int i=0; i<block && b+i<n; ++i){
++cnt0[a[b+i]];
}
} printf("%lld\n",ans);
}
return 0;
}
CodeChef COUNTARI Arithmetic Progressions(分块 + FFT)的更多相关文章
- CodeChef - COUNTARI Arithmetic Progressions (FFT)
题意:求一个序列中,有多少三元组$(i,j,k)i<j<k $ 满足\(A_i + A_k = 2*A_i\) 构成等差数列. https://www.cnblogs.com/xiuwen ...
- [BZOJ 3509] [CodeChef] COUNTARI (FFT+分块)
[BZOJ 3509] [CodeChef] COUNTARI (FFT+分块) 题面 给出一个长度为n的数组,问有多少三元组\((i,j,k)\)满足\(i<j<k,a_j-a_i=a_ ...
- CC countari & 分块+FFT
题意: 求一个序列中顺序的长度为3的等差数列. SOL: 对于这种计数问题都是用个数的卷积来进行统计.然而对于这个题有顺序的限制,不好直接统计,于是竟然可以分块?惊为天人... 考虑分块以后的序列: ...
- bzoj 3509: [CodeChef] COUNTARI] [分块 生成函数]
3509: [CodeChef] COUNTARI 题意:统计满足\(i<j<k, 2*a[j] = a[i] + a[k]\)的个数 \(2*a[j]\)不太好处理,暴力fft不如直接暴 ...
- CodeChef - COUNTARI FTT+分块
Arithmetic Progressions Given N integers A1, A2, …. AN, Dexter wants to know how many ways he can ch ...
- BZOJ 3509: [CodeChef] COUNTARI
3509: [CodeChef] COUNTARI Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 883 Solved: 250[Submit][S ...
- BZOJ3509: [CodeChef] COUNTARI
3509: [CodeChef] COUNTARI Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 339 Solved: 85[Submit][St ...
- [Educational Codeforces Round 16]D. Two Arithmetic Progressions
[Educational Codeforces Round 16]D. Two Arithmetic Progressions 试题描述 You are given two arithmetic pr ...
- Dirichlet's Theorem on Arithmetic Progressions 分类: POJ 2015-06-12 21:07 7人阅读 评论(0) 收藏
Dirichlet's Theorem on Arithmetic Progressions Time Limit: 1000MS Memory Limit: 65536K Total Submi ...
随机推荐
- .NET学习之路----我对P/Invoke技术的理解(一)
看了P/Invoke技术的介绍,于是想写下点东西,东西包含两个部分:知识的纪录和我的理解及疑问. r托管代码中调用非托管API函数的过程 1.定位包含API的DLL: 2.载入DLL 3.找到DLL中 ...
- DiskFileItemFactory类的使用
将请求消息实体中的每一个项目封装成单独的DiskFileItem (FileItem接口的实现) 对象的任务由 org.apache.commons.fileupload.FileItemFact ...
- safari浏览器在window下 打开控制台
有时候需要在window下测试safari浏览器的兼容性 然后需要打开错误控制台 以下是完整打开的图文教程 1.显示菜单栏 2.打开偏好设置 3.然后切换到高级标签 勾选 在菜单栏显示开发菜单 4.打 ...
- CSS3实现阴阳鱼
直接上代码: <!doctype html> <html> <head> <meta charset="utf-8" /> < ...
- [Math & Algorithm] 拉格朗日乘数法
拉格朗日乘数法(Lagrange Multiplier Method)之前听数学老师授课的时候就是一知半解,现在越发感觉拉格朗日乘数法应用的广泛性,所以特意抽时间学习了麻省理工学院的在线数学课程.新学 ...
- 【相当实用】如何让TortoiseSVN导出新增或修改过的文件
当一个网站项目进入运营维护阶段以后,不会再频繁地更新全部源文件到服务器,这个时间的修改大多是局部的,因此更新文件只需更新修改过的文件,其他没有修改过的文件就没有必要上载到服务器.但一个稍微上规模的网站 ...
- python解析git log后生成页面显示git更新日志信息
使用git log可以查到git上项目的更新日志. 如下两个git项目,我想把git的日志信息解析成一个便于在浏览器上查看的页面. https://github.com/gityf/lua https ...
- 一条代码解决各种IE浏览器兼容性问题
在网站开发中不免因为各种兼容问题苦恼,针对兼容问题,其实IE给出了解决方案Google也给出了解决方案百度也应用了这种方案去解决IE的兼容问题 百度源代码如下 <!Doctype html> ...
- word20161209
failback / 故障回复 failback policy / 故障回复策略 failed / 失败 failover / 故障转移 failover policy / 故障转移策略 failov ...
- VS2013编译Qt5.6.0静态库
获取qt5.6.0源码包 直接去www.qt.io下载就好了,这里就不详细说了. 这里是我已经编译好的** 链接:http://pan.baidu.com/s/1pLb6wVT 密码: ak7y ** ...