该题之理论题解,代码打炸了(wa了),就不放了qwq
后来debug出来了,统计排序后第一个询问的答案时,我把1写成i了qwq
首先,我们明显的,我们需要使用莫队算法来维护每个颜色的出现次数,设c[i]表示区间中i出现了多少次,同时我们再维护一个数组d[i]表示出现次数为i的有几个颜色。这两个数组在莫队的每次区间更改中都可以O(1)同时维护,所以如果仅仅维护两个数组的话,复杂度是可行的
那么,现在我们假设维护了这两个数组,我们该怎么统计答案呢?
我们使用类似数据分块的方式,将出现次数分为两部分:
1.出现次数小于等于,因为个只有个,暴力枚举计算即可(使用d数组统计答案)
2.出现次数大于,这里有个小trick:
一段区间内,出现次数大于的点的个数是小于个的,这个大家应该都会证明,就不再说了,那么,我们可以考虑,将这些出现次数大于的颜色直接储存起来,之后再遍历一遍统计答案即可。
那么现在就有个问题了,因为区间变动的时候,部分颜色的出现次数会发生改变,那么,可能会使得部分原本出现次数大于的颜色的出现次数小于了,那么我们就要把它给删去。
那么,现在就主要有两种思路(分别对应我前期和后期的想法):
一.用stl,比如set维护增加和删除,因为判互质的时候要使用gcd函数,带个log,所以我们使用操作复杂度为log的stl对总复杂度是没影响的。
二.用栈之类直接维护
因为每次区间移动后,我们增加的出现次数大于的颜色最多个左右,那么,我们的栈的元素每次最多也就增加个,加上原来的个,个数平均就是级别的,而我们每次又要遍历一遍这些数,那么我们可以把符号条件的数计算答案后加入另一个栈,这样,另一个栈就变成了都是符合条件的元素的情况了,我们把现在的栈O(1)(top=0)清空掉,就相当于询问开始的时候两个栈交换了一下,所以我们可以用类似01滚动的方法,每次用两个栈来分别维护即可~(平均复杂度)
所以总复杂度为
Update:
一个复杂度上的优化
我们一开始,先做一遍线性筛/埃式筛,做出函数g[x],g[x]为x的最小/任意一个质因子。
那么,每次询问时查询时,我们就可以先对k进行质因数分解,把k的所有质因子求出来,分别设为,不难发现,这最多只有7个,于是,我们只需要判断每个询问的数是否是这些数的倍数即可,无需求gcd,复杂度变为:
这是复杂度上的优化,至于实现时产生的常数,则不在我们的考虑之中qwq
代码[1003ms]:
#include<bits/stdc++.h> using namespace std; const int N=50001; int a[N],b[N],c[N],d[N],ans[N]; int e,block,top; int sta[N],stp[N]; bool vis[N]; struct Que{ int l,r,k,x; }q[N]; inline bool kkk(Que x,Que y){ return b[x.l]!=b[y.l]?b[x.l]<b[y.l]:((b[x.l]&1)?b[x.r]<b[y.r]:b[x.r]>b[y.r]); } inline void Insert(int x){ --d[c[x]]; ++c[x]; ++d[c[x]]; if(c[x]==block+1){ if(!vis[x]){ vis[x]=1;sta[++top]=x; } } } inline void Delted(int x){ --d[c[x]]; --c[x]; ++d[c[x]]; } int main(){ int n,m; scanf("%d%d",&n,&m); block=sqrt(n+m); for(int i=1;i<=n;++i){ b[i]=(i-1)/block+1; scanf("%d",&a[i]); } for(int i=1;i<=m;++i){ scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].k); q[i].x=i; } sort(q+1,q+m+1,kkk); int L=q[1].l,R=q[1].r; for(int i=L;i<=R;++i){ Insert(a[i]); } for(int i=1;i<=n;++i){ if(__gcd(q[1].k,i)==1){ ans[q[1].x]+=d[i]; } } for(int i=2;i<=m;++i){ while(L>q[i].l){ Insert(a[--L]); } while(R<q[i].r){ Insert(a[++R]); } while(L<q[i].l){ Delted(a[L++]); } while(R>q[i].r){ Delted(a[R--]); } for(int j=1;j<=block;++j){ if(__gcd(j,q[i].k)==1){ ans[q[i].x]+=d[j]; } } int tot=0; for(int j=1;j<=top;++j){ if(c[sta[j]]>block){ stp[++tot]=sta[j]; if(__gcd(c[sta[j]],q[i].k)==1){ ++ans[q[i].x]; } }else{ vis[sta[j]]=0; } } top=tot; for(int j=1;j<=tot;++j){ sta[j]=stp[j]; } } for(int i=1;i<=m;++i){ printf("%d\n",ans[i]); } return 0; }
代码[235ms]:
#include<bits/stdc++.h> using namespace std; const int N=50001; int a[N],b[N],c[N],d[N],ans[N]; int e,block,top,cnt; int sta[N],stp[N],g[N],zhi[N]; int sp[N],al; bool vis[N];int vit[N]; struct Que{ int l,r,k,x; }q[N]; inline bool kkk(Que x,Que y){ return b[x.l]!=b[y.l]?b[x.l]<b[y.l]:((b[x.l]&1)?b[x.r]<b[y.r]:b[x.r]>b[y.r]); } inline void Insert(int x){ --d[c[x]]; ++c[x]; ++d[c[x]]; if(c[x]==block+1){ if(!vis[x]){ vis[x]=1;sta[++top]=x; } } } inline void sai(){ for(int i=2;i<N;++i){ if(!g[i]){ g[i]=i; zhi[++cnt]=i; } for(int j=1;j<=cnt;++j){ if(i*zhi[j]>=N){ break; } g[i*zhi[j]]=zhi[j]; if(i%zhi[j]==0){ break; } } } } inline void Delted(int x){ --d[c[x]]; --c[x]; ++d[c[x]]; } int main(){ sai(); int n,m; scanf("%d%d",&n,&m); block=sqrt(n+m); for(int i=1;i<=n;++i){ b[i]=(i-1)/block+1; scanf("%d",&a[i]); } for(int i=1;i<=m;++i){ scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].k); q[i].x=i; } sort(q+1,q+m+1,kkk); int L=q[1].l,R=q[1].r; for(int i=L;i<=R;++i){ Insert(a[i]); } for(int i=1;i<=n;++i){ if(__gcd(q[1].k,i)==1){ ans[q[1].x]+=d[i]; } } for(int i=2;i<=m;++i){ while(L>q[i].l){ Insert(a[--L]); } while(R<q[i].r){ Insert(a[++R]); } while(L<q[i].l){ Delted(a[L++]); } while(R>q[i].r){ Delted(a[R--]); } al=0; while(g[q[i].k]){ if(vit[g[q[i].k]]!=i){ vit[g[q[i].k]]=i,sp[++al]=g[q[i].k]; } q[i].k/=g[q[i].k]; } for(int j=1;j<=block;++j){ bool flag=1; for(int p=1;p<=al;++p){ if(j%sp[p]==0){ flag=0; break; } } ans[q[i].x]+=(flag*d[j]); } int tot=0; for(int j=1;j<=top;++j){ if(c[sta[j]]>block){ stp[++tot]=sta[j]; bool flag=1; for(int p=1;p<=al;++p){ if(c[sta[j]]%sp[p]==0){ flag=0; break; } } ans[q[i].x]+=flag; }else{ vis[sta[j]]=0; } } top=tot; for(int j=1;j<=tot;++j){ sta[j]=stp[j]; } } for(int i=1;i<=m;++i){ printf("%d\n",ans[i]); } return 0; }
顺便附带乱搞卡常后,113ms版本[强迫症患者表示很难受,跪求大佬帮忙卡下100ms]:
#pragma GCC optimize(3,"inline","Ofast") #pragma GCC target("sse,sse2,sse3,sse4,sse4.1,sse4.2,avx,avx2,popcnt") #include<bits/stdc++.h> using namespace std; const int N=50001; int a[N],b[N],c[N],d[N],ans[N]; int e,block,top,cnt; int sta[2][N],g[N],zhi[N]; int sp[N],al,vnow; bool vis[N];int vit[N]; inline void read(int &ss){ char ch=getchar();int w=0;ss=0; while(ch<'0'||ch>'9')w|=(ch=='-'),ch=getchar(); while(ch>='0'&&ch<='9')ss=(ss*10+(ch-'0')),ch=getchar(); ss=(w?-ss:ss); } inline void write(int x){ if(x>9)write(x/10); putchar(char(x%10+'0')); } struct Que{ int l,r,k,x; }q[N]; inline bool kkk(Que x,Que y){ return b[x.l]!=b[y.l]?b[x.l]<b[y.l]:((b[x.l]&1)?b[x.r]<b[y.r]:b[x.r]>b[y.r]); } inline void sai(){ for(int i=2;i<N;++i){ if(!g[i]){ g[i]=i; zhi[++cnt]=i; } for(int j=1;j<=cnt;++j){ if(i*zhi[j]>=N){ break; } g[i*zhi[j]]=zhi[j]; if(i%zhi[j]==0){ break; } } } } int main(){ sai(); int n,m; read(n),read(m); block=sqrt(n+m); for(int i=1;i<=n;++i){ b[i]=(i-1)/block+1;read(a[i]); } for(int i=1;i<=m;++i){ read(q[i].l),read(q[i].r),read(q[i].k); q[i].x=i; } sort(q+1,q+m+1,kkk); int L=q[1].l,R=q[1].r; for(int i=L;i<=R;++i){ --d[c[a[i]]]; ++c[a[i]]; ++d[c[a[i]]]; if(c[a[i]]==block+1){ if(!vis[a[i]]){ vis[a[i]]=1;sta[vnow][++top]=a[i]; } } } for(int i=1;i<=n;++i){ if(__gcd(q[1].k,i)==1){ ans[q[1].x]+=d[i]; } } for(int i=2;i<=m;++i){ vnow^=1; while(L>q[i].l){ --L;--d[c[a[L]]];++c[a[L]];++d[c[a[L]]]; if(c[a[L]]==block+1){ if(!vis[a[L]]){ vis[a[L]]=1;sta[vnow][++top]=a[L]; } } } while(R<q[i].r){ ++R;--d[c[a[R]]];++c[a[R]];++d[c[a[R]]]; if(c[a[R]]==block+1){ if(!vis[a[R]]){ vis[a[R]]=1;sta[vnow][++top]=a[R]; } } } while(L<q[i].l){ --d[c[a[L]]];--c[a[L]];++d[c[a[L]]];++L; } while(R>q[i].r){ --d[c[a[R]]];--c[a[R]];++d[c[a[R]]];--R; } al=0; while(g[q[i].k]){ if(vit[g[q[i].k]]!=i){ vit[g[q[i].k]]=i,sp[++al]=g[q[i].k]; } q[i].k/=g[q[i].k]; } for(int j=1;j<=block;++j){ if(!d[j])continue; bool flag=1; for(int p=1;p<=al;++p){ if(j%sp[p]==0){ flag=0; break; } } ans[q[i].x]+=(flag*d[j]); } int tot=0; for(int j=1;j<=top;++j){ if(c[sta[vnow][j]]>block){ sta[vnow^1][++tot]=sta[vnow][j]; bool flag=1; for(int p=1;p<=al;++p){ if(c[sta[vnow][j]]%sp[p]==0){ flag=0; break; } } ans[q[i].x]+=flag; }else{ vis[sta[vnow][j]]=0; } } top=tot; } for(int i=1;i<=m;++i){ write(ans[i]),putchar('\n'); } return 0; }