[数论记录]CFgym102354B. Yet Another Convolution
command_block · · 个人记录
神仙题Orz
题目Link
题意 : 给出两个数组
求
首先
我们又把
看起来一脸不可做……
考虑到经典
我们考虑对于每个
可以看做这种子问题
现在问题就变成了给定数组
这个
如果
对于
我们整体二分的时候,先把
-
把
>mid 的位置都变成1 -
求和,把询问分到两个子区间里。
-
继续分治。
这里我们需要一个数据结构,资瓷求某个数倍数处点权和,带修。
无脑写一个枚举约数就好了,修改
注意到,在分治树上,每个询问都要历经
注意到每次判别都需要
总的复杂度
我们算一下总的复杂度 :
掐指一算,其中两个
代码细节比较少,还是很好写的。居然只跑了800ms……神了
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#define pf printf
#define INF 2000000000
#define MaxN 100500
using namespace std;
inline int read()
{
register int X=0;
register char ch=0;
while(ch<48||ch>57)ch=getchar();
while(ch>=48&&ch<=57)X=X*10+(ch^48),ch=getchar();
return X;
}
vector<int> d[MaxN];
int n,mu[MaxN],p[MaxN],tn;
bool e[MaxN];
void sieve()
{
mu[1]=1;
for (int i=2;i<=n;i++){
if (!e[i])mu[p[++tn]=i]=-1;
for (int j=1,t;j<=tn&&(t=i*p[j])<=n;j++){
e[t]=1;
if (i%p[j]==0)break;
mu[t]=-mu[i];
}
}
for (int i=1;i<=n;i++)
for (int j=1;i*j<=n;j++)
d[i*j].push_back(i);
}
int tp[MaxN],xx[MaxN],s3[MaxN],q[MaxN];
int s1[MaxN],s2[MaxN],tc[MaxN];
void upd(int t,int c)
{
for (int i=0;i<d[t].size();i++)
tc[d[t][i]]+=c;
}
int qry(int t)
{
int ret=0;
for (int i=0;i<d[t].size();i++)
ret+=mu[d[t][i]]*tc[d[t][i]];
return ret;
}
void ltg(int tim)
{
if (tn>tim)
for (int i=tim;i<tn;i++)
upd(tp[i],1);
else
for (int i=tn;i<tim;i++)
upd(tp[i],-1);
tn=tim;
}
int sq[MaxN];
void solve2(int l,int r,int tl,int tr)
{
if (l>r)return ;
if (tl==tr){
for (int i=l;i<=r;i++)s3[q[i]]=tl;
return ;
}int tmid=(tl+tr)>>1,pl=l-1,pr=r+1;
ltg(tmid+1);
for (int i=l;i<=r;i++)
if (qry(q[i])<=0)sq[++pl]=q[i];
else sq[--pr]=q[i];
memcpy(q+l,sq+l,sizeof(int)*(r-l+1));
solve2(l,pl,tl,tmid);
solve2(pr,r,tmid+1,tr);
}
int solve1(int m)
{
memcpy(xx,s2,sizeof(int)*(m+5));
sort(xx+1,xx+m+1);
for (int i=1,sav;i<=m;i++){
sav=upper_bound(xx+1,xx+m+1,s2[i])-xx-1;
tp[sav]=i;xx[sav]++;
}memset(tc,0,sizeof(int)*(m+5));tn=m+1;
for (int i=1;i<=m;i++)q[i]=i;
solve2(1,m,1,m);
int ret=-INF;
for (int i=1;i<=m;i++)
ret=max(ret,s1[i]+xx[s3[i]]-1);
return ret;
}
int a[MaxN],b[MaxN],ans[MaxN];
void solve0()
{
for (int k=1;k<=n;k++){
for (int i=1;i*k<=n;i++)
{s1[i]=a[i*k];s2[i]=b[i*k];}
ans[k]=max(ans[k],solve1(n/k));
}
}
int main()
{
scanf("%d",&n);
sieve();
for (int i=1;i<=n;i++)a[i]=read();
for (int i=1;i<=n;i++)b[i]=-read();
solve0();
for (int i=1;i<=n;i++)
{a[i]=-a[i];b[i]=-b[i];}
solve0();
for (int i=1;i<=n;i++)pf("%d ",ans[i]);
}