zoukankan      html  css  js  c++  java
  • CC countari & 分块+FFT

    题意:

      求一个序列中顺序的长度为3的等差数列.

    SOL:

      对于这种计数问题都是用个数的卷积来进行统计.然而对于这个题有顺序的限制,不好直接统计,于是竟然可以分块?惊为天人...

      考虑分块以后的序列:

        一个块内直接枚举统计三个或两个在块内的.

        只有一个在当前块我们假设它是中间那个,对左右其它块做卷积.

      但是还是感觉复杂度有点玄学啊...

      我比较傻逼...一开始块内统计根本没有想清楚...最后做卷积硬生生把复杂度变成了 $sqrt{N}*N*log(N)$...

      改了一个晚上终于没忍住看标程...我是傻逼明明a的范围比n小...

    CODE:(tle的代码不想改了= =)

      

    /*=================================
    # Created time: 2016-04-19 16:09
    # Filename: cccountari.cpp
    # Description: Ploblem from codechef countari
    =================================*/
    #define me AcrossTheSky&HalfSummer11  
    #include <cstdio>  
    #include <cmath>  
    #include <ctime>  
    #include <string>  
    #include <cstring>  
    #include <cstdlib>  
    #include <iostream>  
    #include <algorithm>  
      
    #include <set> 
    #include <stack>  
    #include <queue>  
    #include <vector>  
      
    #define lowbit(x) (x)&(-x)  
    #define Abs(x) ((x) > 0 ? (x) : (-(x)))  
    #define FOR(i,a,b) for((i)=(a);(i)<=(b);(i)++)  
    #define FORP(i,a,b) for(int i=(a);i<=(b);i++)  
    #define FORM(i,a,b) for(int i=(a);i>=(b);i--)  
    #define ls(a,b) (((a)+(b)) << 1)  
    #define rs(a,b) (((a)+(b)) >> 1)  
    #define getlc(a) ch[(a)][0]  
    #define getrc(a) ch[(a)][1]  
      
    #define maxn 500005 
    #define maxm 100005 
    #define INF 1070000000  
    using namespace std;  
    typedef long long ll;  
    typedef unsigned long long ull;  
      
    template<class T> inline  
    void read(T& num){  
        num = 0; bool f = true;char ch = getchar();  
        while(ch < '0' || ch > '9') { if(ch == '-') f = false;ch = getchar();}  
        while(ch >= '0' && ch <= '9') {num = num * 10 + ch - '0';ch = getchar();}  
        num = f ? num: -num;  
    } 
    int outs[100]; 
    template<class T> inline 
    void write(T x){ 
    	if (x==0) {putchar('0'); putchar(' '); return;} 
    	if (x<0) {putchar('-'); x=-x;} 
    	int num=0; 
    	while (x){ outs[num++]=(x%10); x=x/10;} 
    	FORM(i,num-1,0) putchar(outs[i]+'0'); putchar(' '); 
    } 
    /*==================split line==================*/
    const double pi=acos(-1);
    struct cpx{
        double x,y;
        inline double real(){return x;}
        cpx(double a=0,double b=0):x(a),y(b){}
    }f[maxn],g[maxn],eps[maxn],inv_eps[maxn];
    
    inline cpx operator +(cpx a,cpx b){return cpx(a.x+b.x,a.y+b.y);}
    inline cpx operator -(cpx a,cpx b){return cpx(a.x-b.x,a.y-b.y);}
    inline cpx operator /(cpx a,double b){return cpx(a.x/b,a.y);}
    inline cpx operator *(cpx a,cpx b){return cpx(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
    inline cpx conj(cpx a){return cpx(a.x,-a.y);}
    
    inline void get_eps(int p){
    	double angle=2.0*pi/p;
    	FORP(i,0,p-1) eps[i]=cpx(cos(angle*i),sin(angle*i));
    	FORP(i,0,p-1) inv_eps[i]=conj(eps[i]);
    }
    inline void fft(int n,cpx* buffer,cpx* eps){
    	for (int i = 0, j = 0;i < n; i++){
    		if (i > j) swap(buffer[i],buffer[j]);
    		for (int l = n >> 1;(j ^= l) < l;l >>= 1);
    	}
    	for (int i = 2; i <= n; i <<= 1){
    		int m = i >> 1;
    		for (int j = 0; j < n; j += i)
    			for (int k = 0; k != m; k++){
    				cpx z = buffer[j + m + k] * eps[n / i * k];
    				buffer[j + m + k] = buffer[j + k] - z;
    				buffer[j + k] = buffer[j + k] + z;
    			}
    	}
    }
    ll n,k,block,num;
    ll prec[30004],c[30040],suf[40000];
    //bool vis[40000];
    ll ans=0;
    ll maxa=0;
    struct Range{ ll l,r; } rg[1000];
    struct Infor{ ll val,pos;} a[100005];
    
    int main(){
    	read(n);
    	block=3;
    	if ((int)n/sqrt(n)>3) block=(int)n/sqrt(n);
    	FORP(i,1,n) {
    		read(a[i].val);
    		g[a[i].val].x++;
    		maxa=max(maxa,a[i].val);
    		a[i].pos=(i-1)/block+1;
    		suf[a[i].val]++;
    	}
    	
    	ll k=1; maxa*=2;
    	while (k<maxa) k<<=1;
    	k<<=1;
    	get_eps(k);
    	
    	num=a[n].pos;
    	FORP(i,1,num) rg[i].l=(i-1)*block+1,rg[i].r=min(n,(i)*block);
    	FORP(i,1,num){
    		FORP(j,rg[i].l,rg[i].r) c[a[j].val]++;
    		FORP(l,rg[i].l,rg[i].r-1){
    			suf[a[l].val]--;
    			FORP(r,l+1,rg[i].r) {
    				suf[a[r].val]--;
    				if (a[l].val==a[r].val) ans+=suf[a[l].val]+prec[a[l].val];
    				else
    				{
    					int x=a[l].val-(a[r].val-a[l].val);
    					if (x>0) ans+=prec[x];
    					x=a[r].val+(a[r].val-a[l].val);
    					if (x>0) ans+=suf[x];
    				}
    			}
    			FORP(r,l+1,rg[i].r)	suf[a[r].val]++;
    		}
    		FORP(j,rg[i].l,rg[i].r) prec[a[j].val]+=c[a[j].val],c[a[j].val]=0;
    		suf[a[rg[i].r].val]--;
    	}
    	FORP(i,rg[1].l,rg[1].r) g[a[i].val].x--;
    	FORP(i,2,num-1){
    		//memset(f,0,sizeof(f)); memset(g,0,sizeof(g));
    		FORP(j,rg[i-1].l,rg[i-1].r) f[a[j].val].x++;
    		FORP(j,rg[i-1].l,rg[i-1].r) g[a[j].val].x--;
    		fft(k,f,eps); fft(k,g,eps);
    		FORP(j,0,k-1) f[j]=f[j]*g[j];
    		fft(k,f,inv_eps);
    		FORP(j,rg[i].l,rg[i].r) ans+=(ll)(f[a[j].val+a[j].val].x/k+0.5);
    	}
    	write(ans); puts("");
    }
    

     调下块大小a掉了

    /*=================================
    # Created time: 2016-04-19 16:09
    # Filename: cccountari.cpp
    # Description: Ploblem from codechef countari
    =================================*/
    #define me AcrossTheSky&HalfSummer11  
    #include <cstdio>  
    #include <cmath>  
    #include <ctime>  
    #include <string>  
    #include <cstring>  
    #include <cstdlib>  
    #include <iostream>  
    #include <algorithm>  
      
    #include <set> 
    #include <stack>  
    #include <queue>  
    #include <vector>  
      
    #define lowbit(x) (x)&(-x)  
    #define Abs(x) ((x) > 0 ? (x) : (-(x)))  
    #define FOR(i,a,b) for((i)=(a);(i)<=(b);(i)++)  
    #define FORP(i,a,b) for(int i=(a);i<=(b);i++)  
    #define FORM(i,a,b) for(int i=(a);i>=(b);i--)  
    #define ls(a,b) (((a)+(b)) << 1)  
    #define rs(a,b) (((a)+(b)) >> 1)  
    #define getlc(a) ch[(a)][0]  
    #define getrc(a) ch[(a)][1]  
      
    #define maxn 100005 
    #define maxm 100005 
    #define INF 1070000000  
    using namespace std;  
    typedef long long ll;  
    typedef unsigned long long ull;  
      
    template<class T> inline  
    void read(T& num){  
        num = 0; bool f = true;char ch = getchar();  
        while(ch < '0' || ch > '9') { if(ch == '-') f = false;ch = getchar();}  
        while(ch >= '0' && ch <= '9') {num = num * 10 + ch - '0';ch = getchar();}  
        num = f ? num: -num;  
    } 
    int outs[100]; 
    template<class T> inline 
    void write(T x){ 
    	if (x==0) {putchar('0'); putchar(' '); return;} 
    	if (x<0) {putchar('-'); x=-x;} 
    	int num=0; 
    	while (x){ outs[num++]=(x%10); x=x/10;} 
    	FORM(i,num-1,0) putchar(outs[i]+'0'); //putchar(' '); 
    } 
    /*==================split line==================*/
    const double pi=acos(-1);
    struct cpx{
        double x,y;
        cpx(double a=0,double b=0):x(a),y(b){}
    }f[maxn],g[maxn],eps[maxn],inv_eps[maxn];
    
    inline cpx operator +(cpx a,cpx b){return cpx(a.x+b.x,a.y+b.y);}
    inline cpx operator -(cpx a,cpx b){return cpx(a.x-b.x,a.y-b.y);}
    inline cpx operator *(cpx a,cpx b){return cpx(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
    inline cpx conj(cpx a){return cpx(a.x,-a.y);}
    
    inline void get_eps(int p){
    	double angle=2.0*pi/p;
    	FORP(i,0,p-1) eps[i]=cpx(cos(angle*i),sin(angle*i));
    	FORP(i,0,p-1) inv_eps[i]=conj(eps[i]);
    }
    inline void fft(int n,cpx* buffer,cpx* eps){
    	for (int i = 0, j = 0;i < n; i++){
    		if (i > j) swap(buffer[i],buffer[j]);
    		for (int l = n >> 1;(j ^= l) < l;l >>= 1);
    	}
    	for (int i = 2; i <= n; i <<= 1){
    		int m = i >> 1;
    		for (int j = 0; j < n; j += i)
    			for (int k = 0; k != m; k++){
    				cpx z = buffer[j + m + k] * eps[n / i * k];
    				buffer[j + m + k] = buffer[j + k] - z;
    				buffer[j + k] = buffer[j + k] + z;
    			}
    	}
    }
    int n,k,block,num;
    int prec[30010],c[30010],suf[30100];
    ll ans=0;
    int maxa=0;
    struct Range{ int l,r; } rg[10000];
    struct Infor{ int val,pos;} a[maxn];
    
    int main(){
    	read(n);
    	block=4000;
    	//if ((ll)n/sqrt(n)>3) block=(ll)n/sqrt(n);
    	block=min(block,n);
    	FORP(i,1,n) {
    		read(a[i].val);
    		maxa=max(maxa,a[i].val);
    		a[i].pos=(i-1)/block+1;
    		suf[a[i].val]++;
    	}
    	
    	int k=1; //maxa*=2;
    	while (k<maxa) k<<=1;
    	k<<=1;
    	get_eps(k);
    	
    	num=a[n].pos;
    	FORP(i,1,num) rg[i].l=(i-1)*block+1,rg[i].r=(i)*block; rg[num].r=n;
    	FORP(i,1,num){
    		FORP(j,rg[i].l,rg[i].r) c[a[j].val]++;
    		FORP(l,rg[i].l,rg[i].r-1){
    			suf[a[l].val]--;
    			FORP(r,l+1,rg[i].r) {
    				suf[a[r].val]--;
    				if (a[l].val==a[r].val) ans+=suf[a[l].val]+prec[a[l].val];
    				else
    				{
    					int x=a[l].val-(a[r].val-a[l].val);
    					if (x>0 && x<=maxa) ans+=prec[x];
    					x=a[r].val+(a[r].val-a[l].val);
    					if (x>0 && x<=maxa) ans+=suf[x];
    				}
    			}
    			FORP(r,l+1,rg[i].r)	suf[a[r].val]++;
    		}
    		suf[a[rg[i].r].val]--;
    		FORP(j,0,maxa) f[j]=cpx(prec[j],0),g[j]=cpx(suf[j],0);
    		FORP(j,maxa+1,k) f[j]=cpx(0.0,0),g[j]=cpx(0.0,0);
    		fft(k,f,eps); fft(k,g,eps);
    		FORP(j,0,k-1) f[j]=f[j]*g[j];
    		fft(k,f,inv_eps);
    		FORP(j,rg[i].l,rg[i].r) ans+=trunc(f[a[j].val+a[j].val].x/k+0.5);
    		
    		FORP(j,rg[i].l,rg[i].r) prec[a[j].val]+=c[a[j].val],c[a[j].val]=0;
    		
    	}
    	/*FORP(i,2,num-1){
    		memset(f,0,sizeof(f)); memset(g,0,sizeof(g));
    		FORP(j,1,rg[i].l-1) f[a[j].val].x++;
    		FORP(j,rg[i].r+1,n) g[a[j].val].x++;
    		fft(k,f,eps); fft(k,g,eps);
    		FORP(j,0,k-1) f[j]=f[j]*g[j];
    		fft(k,f,inv_eps);
    		//FORP(j,0,maxa) printf("%d ",(int)(f[j].x/k+0.5)); puts("");
    		FORP(j,rg[i].l,rg[i].r) ans+=(int)(f[a[j].val+a[j].val].x/k+0.5);
    	}*/
    	write(ans); puts("");
    	//printf("%lf",clock()-t);
    }
    
  • 相关阅读:
    如何向线程传递参数
    IntelliJ IDEA 13 Keygen
    单链表的基本操作
    顺序表静态查找
    有向图的十字链表表存储表示
    BF-KMP 算法
    图的邻接表存储表示(C)
    二叉树的基本操作(C)
    VC远控(三)磁盘显示
    Android 数独游戏 记录
  • 原文地址:https://www.cnblogs.com/YCuangWhen/p/5411035.html
Copyright © 2011-2022 走看看