首页 > 代码库 > [Codechef November Challenge 2012] Arithmetic Progressions
[Codechef November Challenge 2012] Arithmetic Progressions
题意:给定一个序列,求多少个三元组满足ai+ak=2*aj(i<j<k)。
题解:原来叉姐的讲义上有啊。。完全忘掉了。。
首先这个式子很明显是一个卷积。我们有了FFT的思路。但是肯定不能每一个数都去做一次。那怎么办呢?我们分块吧!(分块大法好)
对于每一个块我们统计出前面块的桶,同理我们也有后面块的桶,两个桶FFT一下我们就得到了以这个块内元素为j,i和k分别在前面的块与后面的块的方案了。然后我们还要解决两个在一个块,三个在一个块的问题。两个在一个块的我们直接去前后的桶里找,同一个块的直接n*n暴力。然后就做完啦!好妙啊!
这题被坑了好久。。因为空间莫名其妙的问题怎么都算不对(块开极端都可以,就是开中间不行),然后一个下午没有了。。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define LL long long 4 #define N 205005 5 #define INF 1e9 6 #define Bl 70 7 #define LIM 60000 8 const double PI=acos(-1); 9 10 inline LL read(){ 11 LL x=0,f=1; char a=getchar(); 12 while(a<‘0‘ || a>‘9‘) {if(a==‘-‘) f=-1; a=getchar();} 13 while(a>=‘0‘ && a<=‘9‘) x=x*10+a-‘0‘,a=getchar(); 14 return x*f; 15 } 16 17 namespace FFT{ 18 int rev[N]; 19 20 struct vec{ 21 double r,i; 22 vec operator * (const vec& w){return (vec){r*w.r-i*w.i,i*w.r+r*w.i};} 23 vec operator + (const vec& w){return (vec){r+w.r,i+w.i};} 24 vec operator - (const vec& w){return (vec){r-w.r,i-w.i};} 25 }A[N],B[N]; 26 27 inline void fft(vec* x,int len,int f){ 28 for(int i=1;i<=len;i++) if(i<rev[i]) swap(x[i],x[rev[i]]); 29 for(int lnow=2;lnow<=len;lnow<<=1){ 30 vec w,w0=(vec){cos(2.0*PI/lnow*f),sin(2.0*PI/lnow*f)},t1,t2; 31 for(int i=0;i<len;i+=lnow){ 32 w=(vec){1,0}; 33 for(int j=i;j<i+lnow/2;j++){ 34 t1=x[j]; t2=w*x[j+lnow/2]; 35 x[j]=t1+t2; x[j+lnow/2]=t1-t2; 36 w=w*w0; 37 } 38 } 39 } 40 } 41 42 inline void work(int a[],int b[],int l1,int l2,LL s[]){ 43 int len,t; 44 for(len=1,t=0;len<=(l1+l2+1);len<<=1,t++); t=1<<(t-1); 45 for(int i=0;i<=len;i++) rev[i]=rev[i>>1]>>1|(i&1?t:0); 46 for(int i=0;i<=len;i++) B[i]=A[i]=(vec){0,0}; 47 for(int i=0;i<=l1;i++) A[i].r=a[i]; 48 for(int i=0;i<=l2;i++) B[i].r=b[i]; 49 fft(A,len,1); fft(B,len,1); 50 for(int i=0;i<=len;i++) A[i]=A[i]*B[i]; 51 fft(A,len,-1); 52 for(int i=0;i<=l1+l2;i++) 53 s[i]=(LL)(1.0*A[i].r/len+0.5); 54 } 55 56 } 57 58 int n,block_size,block_num; 59 int bel[N],l[Bl+5],r[Bl+5],a[N]; 60 LL tot,ans[2*LIM+6000]; 61 int lsum[LIM+5],rsum[LIM+5],cnt[2*LIM+5]; 62 63 inline void brutal_force(int x){ 64 for(int i=l[x];i<=r[x];i++) rsum[a[i]]--; 65 memset(ans,0,sizeof(ans)); 66 FFT::work(lsum,rsum,30000,30000,ans); 67 for(int i=l[x];i<=r[x];i++){ 68 tot+=ans[2*a[i]]; 69 for(int j=l[x];j<i;j++) 70 if(2*a[i]-a[j]>0) tot+=rsum[2*a[i]-a[j]]; 71 for(int j=i+1;j<=r[x];j++) 72 if(2*a[i]-a[j]>0) tot+=lsum[2*a[i]-a[j]]; 73 } 74 for(int i=l[x];i<=r[x];i++) lsum[a[i]]++; 75 memset(cnt,0,sizeof(cnt)); 76 for(int i=l[x];i<=r[x];i++){ 77 tot+=cnt[a[i]]; 78 for(int j=l[x];j<i;j++) 79 if(2*a[i]-a[j]>0) cnt[2*a[i]-a[j]]++; 80 } 81 } 82 83 int main(){ 84 n=read(); block_size=1500; 85 block_num=(n-1)/block_size+1; 86 for(int i=1;i<=n;i++) a[i]=read(),bel[i]=(i-1)/block_size+1; 87 for(int i=1;i<=block_num;i++) l[i]=(i-1)*block_size+1,r[i]=min(n,i*block_size); 88 for(int i=1;i<=n;i++) rsum[a[i]]++; 89 for(int i=1;i<=block_num;i++) brutal_force(i); 90 printf("%lld\n",tot); 91 return 0; 92 }
[Codechef November Challenge 2012] Arithmetic Progressions
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。