Loading [MathJax]/jax/output/CommonHTML/autoload/multiline.js
潜龙未见静水流,沉默深藏待时秋。一朝破空声势振,惊世骇俗展雄猷。
随笔 - 79, 文章 - 0, 评论 - 2, 阅读 - 1829

CF102354B Yet Another Convolution 题解

目录

题目描述

给定长为 nn 的数列 a,ba,b ,求数列 cc 满足:

ck=maxgcd(i,j)=k|aibj|

数据范围

  • 1n105,1ai,bi109

时间限制 6s ,空间限制 256MB

分析

别被题目名字带偏了,这道题跟卷积没有一点关系。

如果我们能快速求出 c1 ,仅保留下标为 k 的位置,我们就能求出 ck 。因此接下来只需考虑 c1 ,最终复杂度就是求 c1 的复杂度套上调和级数的一只 log

固定 i ,目标变为对 1in ,求 maxgcd(i,j)=1bjmingcd(i,j)=1bj 。后者将 ai,bi 取相反数即可变成前者,因此接下来只需计算 maxgcd(i,j)=1bj

看到 gcd 基本上就要去想莫比乌斯反演,但 max 没有可减性。

二分答案将 max 转化为求和,只需求 f(i)=gcd(i,j)=1[bj>mid]

由于要对所有 i 一起求答案,所以需要整体二分。

S={jbj>mid} ,则:

f(i)=jS[gcd(i,j)=1]=jSd|i,d|jμ(d)

枚举 jS 的因子 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;
}

posted on   peiwenjun  阅读(15)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 上周热点回顾(2.17-2.23)

导航

< 2025年2月 >
26 27 28 29 30 31 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 1
2 3 4 5 6 7 8
点击右上角即可分享
微信分享提示