CF102354B Yet Another Convolution 题解
目录
题目描述
给定长为 nn 的数列 a,ba,b ,求数列 cc 满足:
数据范围
- 1≤n≤105,1≤ai,bi≤109 。
时间限制 6s ,空间限制 256MB 。
分析
别被题目名字带偏了,这道题跟卷积没有一点关系。
如果我们能快速求出 c1 ,仅保留下标为 k 的位置,我们就能求出 ck 。因此接下来只需考虑 c1 ,最终复杂度就是求 c1 的复杂度套上调和级数的一只 log 。
固定 i ,目标变为对 ∀1≤i≤n ,求 maxgcd(i,j)=1bj 和 mingcd(i,j)=1bj 。后者将 ai,bi 取相反数即可变成前者,因此接下来只需计算 maxgcd(i,j)=1bj 。
看到 gcd 基本上就要去想莫比乌斯反演,但 max 没有可减性。
二分答案将 max 转化为求和,只需求 f(i)=∑gcd(i,j)=1[bj>mid] 。
由于要对所有 i 一起求答案,所以需要整体二分。
记 S={j∣bj>mid} ,则:
枚举 j∈S 的因子 d ,将 μ(d) 的贡献加入桶中,计算 f(i) 的贡献时只需枚举 i 的因子即可。
代码实现时,二分判定结束优先递归左边,因为 mid 减小时 S 中的元素依然会产生贡献,撤销以后再递归右边。
分析一下时间复杂度,整体二分的每一层我们要枚举 j 的因子维护桶,再枚举 i 的因子统计答案。
枚举因子的代价为 O(nlogn) ,离散化后整体二分共有 logn 层,再加上最外层调和级数带来的一只 log ,时间复杂度 O(nlog3n) 。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5,inf=1e9;
int n,cnt;
int a[maxn],b[maxn],c[2*maxn],p[maxn],buc[maxn],res[maxn];
int mu[maxn],ta[maxn],tb[maxn],tc[maxn];
vector<int> vec[maxn];
void init(int n)
{
bitset<maxn> b;
mu[1]=1;
for(int i=2,cnt=0;i<=n;i++)
{
if(!b[i]) p[++cnt]=i,mu[i]=-1;
for(int j=1;j<=cnt&&i*p[j]<=n;j++)
{
b[i*p[j]]=1;
if(i%p[j]==0) break;
mu[i*p[j]]=-mu[i];
}
}
for(int i=1;i<=n;i++) for(int j=i;j<=n;j+=i) vec[j].push_back(i);
}
void solve(int l,int r,vector<int> q,vector<int> s)
{
if(q.empty()) return ;
if(l==r)
{
for(auto i:q) tc[i]=l;
return ;
}
int mid=(l+r)>>1;
vector<int> q1,q2,s1,s2;
for(auto i:s)
if(tb[i]>mid)
{
s2.push_back(i);
for(auto d:vec[i]) buc[d]+=mu[d];
}
else s1.push_back(i);
for(auto i:q)
{
int cur=0;
for(auto d:vec[i]) cur+=buc[d];
cur?q2.push_back(i):q1.push_back(i);
}
solve(l,mid,q1,s1);
for(auto i:s2) for(auto d:vec[i]) buc[d]-=mu[d];
solve(mid+1,r,q2,s2);
}
int work(int n)
{
vector<int> vec(n);
iota(vec.begin(),vec.end(),1);
solve(1,cnt,vec,vec);
int res=0;
for(int i=1;i<=n;i++) res=max(res,c[tc[i]]-c[ta[i]]);
return res;
}
int main()
{
scanf("%d",&n),init(n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),c[++cnt]=a[i];
for(int i=1;i<=n;i++) scanf("%d",&b[i]),c[++cnt]=b[i];
sort(c+1,c+cnt+1),cnt=unique(c+1,c+cnt+1)-c-1;
for(int i=1;i<=n;i++) a[i]=lower_bound(c+1,c+cnt+1,a[i])-c,b[i]=lower_bound(c+1,c+cnt+1,b[i])-c;
for(int x=0;x<=1;x++)
{
if(x)
{
reverse(c+1,c+cnt+1);
for(int i=1;i<=cnt;i++) c[i]=inf-c[i];
for(int i=1;i<=n;i++) a[i]=cnt+1-a[i],b[i]=cnt+1-b[i];
}
for(int i=1;i<=n;i++)
{
for(int j=1;i*j<=n;j++) ta[j]=a[i*j],tb[j]=b[i*j];
res[i]=max(res[i],work(n/i));
}
}
for(int i=1;i<=n;i++) printf("%d ",res[i]);
return 0;
}
本文来自博客园,作者:peiwenjun,转载请注明原文链接:https://www.cnblogs.com/peiwenjun/p/18505344
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)