首页 > 其他分享 >CF102354B Yet Another Convolution 题解

CF102354B Yet Another Convolution 题解

时间:2024-10-26 23:32:41浏览次数:4  
标签:gcd int 题解 mid CF102354B maxn vec auto Yet

题目描述

给定长为 \(n\) 的数列 \(a,b\) ,求数列 \(c\) 满足:

\[c_k=\max_{\gcd(i,j)=k}|a_i-b_j|\\ \]

数据范围

  • \(1\le n\le 10^5,1\le a_i,b_i\le 10^9\) 。

时间限制 \(\texttt{6s}\) ,空间限制 \(\texttt{256MB}\) 。

分析

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

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

固定 \(i\) ,目标变为对 \(\forall 1\le i\le n\) ,求 \(\max\limits_{\gcd(i,j)=1}b_j\) 和 \(\min\limits_{\gcd(i,j)=1}b_j\) 。后者将 \(a_i,b_i\) 取相反数即可变成前者,因此接下来只需计算 \(\max\limits_{\gcd(i,j)=1}b_j\) 。

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

二分答案将 \(\max\) 转化为求和,只需求 \(f(i)=\sum\limits_{\gcd(i,j)=1}[b_j\gt mid]\) 。

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

记 \(S=\{j\mid b_j\gt mid\}\) ,则:

\[f(i)=\sum_{j\in S}[\gcd(i,j)=1]=\sum_{j\in S}\sum_{d|i,d|j}\mu(d)\\ \]

枚举 \(j\in S\) 的因子 \(d\) ,将 \(\mu(d)\) 的贡献加入桶中,计算 \(f(i)\) 的贡献时只需枚举 \(i\) 的因子即可。

代码实现时,二分判定结束优先递归左边,因为 \(mid\) 减小时 \(S\) 中的元素依然会产生贡献,撤销以后再递归右边。

分析一下时间复杂度,整体二分的每一层我们要枚举 \(j\) 的因子维护桶,再枚举 \(i\) 的因子统计答案。

枚举因子的代价为 \(\mathcal O(n\log n)\) ,离散化后整体二分共有 \(\log n\) 层,再加上最外层调和级数带来的一只 \(\log\) ,时间复杂度 \(\mathcal O(n\log^3n)\) 。

#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;
}

标签:gcd,int,题解,mid,CF102354B,maxn,vec,auto,Yet
From: https://www.cnblogs.com/peiwenjun/p/18505344

相关文章

  • 洛谷 P5738 【深基7.例4】歌唱比赛 C语言 题解
    题目描述n(n≤100)n(n≤100) 名同学参加歌唱比赛,并接受 m(m≤20)m(m≤20) 名评委的评分,评分范围是 00 到 1010 分。这名同学的得分就是这些评委给分中去掉一个最高分,去掉一个最低分,剩下 m−2m−2 个评分的平均数。请问得分最高的同学分数是多少?评分保留 22 位小数......
  • CSP-J 2024第二轮试题解析
    2024年10月26日,CSP-J/S2024第二轮认证圆满结束;这次入门组的比赛重点考察了模拟和动态规划算法,还涉及到字符串、贪心、前缀和等内容的考察,相比去年来说,对思维能力的考察更多。前两题比去年好做,第三题的部分分也比较好拿,但是第四题的难度明显比去年高,预计分数线会出现小幅提升。......
  • 如何利用递归和迭代构建二叉树?详解题解
    文章目录根据二叉树创建字符串思路代码二叉树的层序遍历思路代码二叉树的最近公共祖先思路代码二叉搜索树与双向链表思路代码从前序与中序遍历序列构造二叉树思路代码总结根据二叉树创建字符串题目:样例:可以看见,唯一特殊的就是左子树,当右子树存在的时候左......
  • 2024CSP-J题解附源码T1-T3
    T1#include<bits/stdc++.h>usingnamespacestd;///T1题解///输入行数n///输入n行,每行一个字符串,字符串只有两个字母组成,第一个字母是花色,第二个字母是点数。///一副牌只有52种组合,因为map能去重,所以用map进行统计不同组合数即mp.size()///结果为52-mp.size()map<string......
  • CF771A. Bear and Friendship Condition 题解 并查集
    题目链接:https://codeforces.com/problemset/problem/771/A视频讲解:https://www.bilibili.com/video/BV1tZ1FYPELp/?p=6题目大意:判断一个无向图中的每个连通块是否都是一个完全图。首先我们可以用并查集维护每个连通块的大小。其次,我们可以开一个\(cnt_i\)表示以节点\(i\)......
  • Codeforces Round 981 (Div. 3) 10.24 (ABCDE)题解
    CodeforcesRound981(Div.3)2024.10.24题解A.SakurakoandKosuke题意:\(Sakurako\)与\(Kosuke\)正在玩游戏,一个点在原点\(x=0\)的起始位置。对于第\(i\)次操作,点会移动\(2\asti-1\)步。两人轮流操作,Sakurako先手,每次将点往负方向移动;Kosuke每次将点往正方向移动......
  • 题解:CF599B Spongebob and Joke
    完整题意详见题面。已知$b_i=f_{a_i}$,求数组$a$的值。先记录每个$f_i$的值的数量,当$f$数组中与$b$数组中没有相同的值时,输出Impossible当$f$数组中与$b$数组中有多组相同的值时,输出Ambiguity其余情况输出Possible。然后考虑如何求出数组$a$,对于$......
  • UVA11294 Wedding 题解
    洛谷题目传送门前排提示:本题需要用到知识点2-SAT以及强联通分量,模板传送门P4782【模板】2-SAT。题目大意:有至多303030对夫妻将会参加一个婚宴。他们将会坐在一个......
  • ctfshow web入门命令执行——web29-40题解
    web291.传入c参数来进行代码执行,payload: c=system("catfla*.php");  如图2.浏览器默认不显示php的标签所以需要右键查看源代码web30题目过滤了命令执行函数system,还可以用passthur(),过滤的字符可以用?代替单个字符。payload:?c=passthur("catfla?.p?p");查看源......
  • Anaconda + Vscode 和 Anaconda + Pycharm安装操作教程以及问题解决
    1.anaconda安装2.打不开AnacondaNavigation解决办法3.如何创建虚拟环境(2种方法)4.Anaconda+vscode5.Anaconda+pycharmAnaconda+Vscode和Anaconda+Pycharm安装操作教程以及问题解决1.anaconda安装Anaconda下载地址我选的是2020,11的一个版本。还没装之前电脑是有p......