CF1028H Make Square

*2900!

考虑把每个数质因数分解,每个质数指数模 2,对于 x,y 的答案是什么?是不是假如 2 边的质数指数只有 1 个为 1 的质数个数。

具体的,记 fxx 分解后指数模 21 的个数,那么 fx+fy 是不是 2 边同时为 1 就不需要减去?如何保留 2 边共同的 1?显然 gcd(x,y),所以 ans=fx+fy2fgcd(x,y)

考虑 5e6 内质数个数最多 7 个,因为从 2 开始连续 8 个质数积大于 5e6

那么 maxd(ai)=27,in

接下来自然想到枚举 gcd,因为每个数的约数不多,显然需要上一个数 y,d|ay 的位置,又因为答案跟 f 有关,f 最大为 7,考虑扫描线,到 i 时枚举约数,再定义 fi,j 为当前扫描下, gcdj 时,满足 j|ax 的最大 x。那么只要枚举一下就好了,接下来变成一个更新操作有 n7128 次,查询操作有 m 次的单点更新,区间最小值,发现是不平衡的。我们直接使用 O(1) 修改,O(n) 查询分块即可。

这里补一个东西:

假如 gcd(x,y)=d,但是枚举到 k,k|d 时,因为 fk<fd 所以显然不会对最小值有影响。

不过确实跑的挺慢的(发现忘了关同步流,关了之后还是能在时限一半内通过的)。

#include <bits/stdc++.h> //#define int long long #define pb push_back using namespace std; const int N=(int)(1e6+5),M=5040000; bool vis[M]; int pri[M>>1],cnt; int n,m,a[N],f[M]; namespace MI { int mi[1000],val[N],id[N],bl,L[1000],R[1000]; void init() { bl=sqrt(n); for(int i=1;i<=n;i++) id[i]=(i-1)/bl+1; for(int i=1;i<=id[n];i++) mi[i]=0x3f3f3f3f,L[i]=(i-1)*bl+1,R[i]=i*bl; R[id[n]]=n; for(int i=1;i<=n;i++) val[i]=0x3f3f3f3f; } void upt(int x,int v) { val[x]=min(val[x],v); mi[id[x]]=min(mi[id[x]],v); } int qry(int l,int r) { if(id[l]==id[r]) { int res=0x3f3f3f3f; for(int i=l;i<=r;i++) res=min(res,val[i]); return res; } else { int res=0x3f3f3f3f; for(int i=l;i<=R[id[l]];i++) res=min(res,val[i]); for(int i=id[l]+1;i<id[r];i++) res=min(res,mi[i]); for(int i=L[id[r]];i<=r;i++) res=min(res,val[i]); return res; } } } void init() { for(int i=2;i<=M-5;i++) { if(!vis[i]) pri[++cnt]=i; for(int j=1;j<=cnt&&pri[j]*i<=M-5;j++) { vis[i*pri[j]]=1; if(i%pri[j]==0) break ; } } } int gcd(int x,int y) { return !y?x:gcd(y,x%y); } vector<pair<int,int> >vec[N]; int tmp[10],ans[N*5],sum[N],st[20][N]; vector<int>vecd[N]; inline int qry(int l,int r) { int qwq=log2(r-l+1); return min(st[qwq][l],st[qwq][r-(1<<qwq)+1]); } int mp[8][M]; signed main() { cin.tie(0); ios::sync_with_stdio(false); cin>>n>>m; init(); for(int i=1;i<=n;i++) { int x,sz=0; cin>>x; int res=1; for(int j=1;j<=cnt&&pri[j]*pri[j]<=x;j++) { if(x%pri[j]) continue ; int qwq=0; while(x%pri[j]==0) x/=pri[j],++qwq; if(qwq&1) tmp[++sz]=pri[j],res*=pri[j]; } if(x!=1) res*=x,tmp[++sz]=x; for(int S=1;S<=(1<<sz)-1;S++) { int qwq=1; for(int j=0;j<sz;j++) { if((S>>j)&1) { qwq*=tmp[j+1]; } } // ++mp[qwq]; if(mp[qwq]==2) vecd.pb(qwq); vecd[i].pb(qwq); } vecd[i].pb(1); if(res!=1) a[i]=res; } for(int i=1;i<=M-5;i++) { int x=i,num=0; for(int j=1;j<=cnt&&pri[j]*pri[j]<=x;j++) { if(x%pri[j]) continue ; int qwq=0; while(x%pri[j]==0) x/=pri[j],++qwq; if(qwq&1) ++num; } if(x!=1) ++num; f[i]=num; } memset(ans,0x3f,sizeof(ans)); memset(st,0x3f,sizeof(st)); for(int i=1;i<=n;i++) sum[i]=sum[i-1]+(a[i]==0); for(int i=1;i<=n;i++) { if(!a[i]) st[0][i]=0x3f3f3f3f; else st[0][i]=f[a[i]]; } for(int i=1;(1<<i)<=n;i++) { for(int j=1;j+(1<<i)-1<=n;j++) { st[i][j]=min(st[i-1][j],st[i-1][j+(1<<(i-1))]); } } for(int i=1;i<=m;i++) { int x,y; cin>>x>>y; if(sum[y]-sum[x-1]>=2) ans[i]=0; else if(sum[y]-sum[x-1]==1) { ans[i]=qry(x,y); } vec[y].pb(make_pair(x,i)); } MI::init(); for(int i=1;i<=n;i++) { for(int d:vecd[i]) { for(int j=0;j<=7;j++) { int p=mp[j][d]; if(p) MI::upt(mp[j][d],f[a[i]]+f[a[p]]-2*f[d]); } } for(int d:vecd[i]) { mp[f[a[i]]][d]=i; } for(auto x:vec[i]) ans[x.second]=min(ans[x.second],MI::qry(x.first,i)); } for(int i=1;i<=m;i++) cout<<ans[i]<<'\n'; return 0; }

__EOF__

本文作者F x o r G
本文链接https://www.cnblogs.com/xugangfan/p/16479033.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   FxorG  阅读(25)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示