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); }
Sometimes it s the very people who no one imagines anything of. who do the things that no one can imagine.