首页 > 其他分享 >区间同余问题

区间同余问题

时间:2024-12-07 17:11:02浏览次数:8  
标签:return gcd int times 问题 GCD 区间 同余

区间同余问题

例题 :CF2050F Maximum modulo equality

题意

给定一个长度为 \(n\) 的序列 \({a_n}\),有 \(Q\) 个询问,每次询问给定一个区间 \([l,r]\) ,让你找一个最大的 \(m\),使得区间内所有的 \(a_i\mod m\) 相同,可以证明一定存在这样一个 \(m\) (\(1\))。

分析

看着很头痛,因为完全不知道从哪里入手,所以只做了这样一个转化 \(a_i=k_i\times m+t\),然后就不知道该怎么办了。
假设这样一个 \(m\) 满足题意的话,那么所有的 \(a_i\) 其实都必须可以写成这样的形式,也就是 \(a_l=k_l\times m+t,a_{l+1}=k_{l+1}\times m+t,...,a_r=k_r\times m+t\),变量的个数仍然比较多,还是没有任何头绪啊。
这时候你会发现这实际上是一个线性方程组,从线性代数的角度思考,实际上任意两个非齐次方程相减就可以得到一个齐次方程,虽然和这个地方差别还是很大,不过可以尝试去沿袭这个思路。
比如对于 \(a_1,a_2\) 来说,把两个等式相减,有 \(abs(a_1-a_2)==abs(k_1-k_2)\times m\),这就意味着 \(m\) 一定是 \(abs(a_1-a_2)\) 的因子。那么我们只需要保证 \([l,r]\) 内的 \(n^2\) 对都满足这个条件即可,也就是求这 \(n^2\) 对的 GCD,但是这会超时,仔细思考,\(n^2\) 对是不是太多了?实际上我们只需要对每一对相邻的进行这种操作,就可以保证所有对都可以被线性表示出来,也自然就满足了所有的限制(这个地方自己推一下就知道了)。

考虑 \(m\) 可以无限大的情况,肯定是区间每一个数都相等,这时候根据算法算出来的是 \(0\),刚好也和题目要求契合了。

时间复杂度允许的情况下可以直接 \(O(n)\) 查询,但是如果只能 \(O(\log n)\) 以下的话,只能用一些RMQ了。
但是这样就要注意,在合并两个区间的时候,不能直接把两份答案gcd起来,这样的话,并不能保证每一对都满足限制条件,比如各从两个区间内选一个,那么就不是满足的。因此我们在合并两个区间的时候还要注意 随便从两个区间里面分别取一个数gcd一下,然后丢到答案的GCD里面去。
这里ST表取的直接就是 \(a_l,a_r\),线段树取的是 \(a_{mid},a_{mid+1}\) 。

注意

gcd不能写成 return x%y==0?y:gcd(y,x%y) 。不然会RE。

Code_ST

#include<bits/stdc++.h>
using namespace std;
inline int gcd(int x,int y){return y==0?x:gcd(y,x%y);}
int T,n,q,l,r;
int a[200010],c[200010];
int GCD[200010][22];
inline int query(int l,int r)
{
    if(l==r)return 0;
    int loglen=(int)log2(r-l+1);
    // cout<<l<<' '<<r<<' '<<loglen<<'\n';
    // cout<<a[l]<<' '<<a[r]<<' '<<GCD[l][loglen]<<' '<<GCD[r-(1<<loglen)+1][loglen]<<'\n';
    return gcd(abs(a[l]-a[r]),gcd(GCD[l][loglen],GCD[r-(1<<loglen)+1][loglen]));
}
inline void solve()
{
    cin>>n>>q;
    for(int i=1;i<=n;++i)cin>>a[i];
    for(int j=1;(1<<j)<=n;++j)
    {
        for(int i=1;i+(1<<j)-1<=n;++i)
        {
            if(j>1)GCD[i][j]=gcd(abs(a[i]-a[i+(1<<j-1)]),gcd(GCD[i][j-1],GCD[i+(1<<j-1)][j-1]));
            else GCD[i][j]=abs(a[i]-a[i+(1<<j-1)]);
        }
    }
    while(q--)
    {
        cin>>l>>r;
        // query(l,r);
        cout<<query(l,r)<<'\n';
    }
    cout<<'\n';
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>T;
    while(T--)
    {
        solve();
    }
    return 0;
}

COde_Seg

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
struct SEG
{
    int l,r,val;
}tr[N<<2];
int a[N];
int T,n,q,l,r;
inline int gcd(int x,int y){return y==0?x:gcd(y,x%y);}
inline void pu(int x)
{
    tr[x].val=gcd(abs(a[tr[x].l]-a[tr[x].r]),gcd(tr[x<<1].val,tr[x<<1|1].val));
}
inline void build(int x,int l,int r)
{
    tr[x].l=l,tr[x].r=r;
    if(l==r){tr[x].val=0;return ;}
    int mid=l+r>>1;
    build(x<<1,l,mid),build(x<<1|1,mid+1,r);
    pu(x);
}
inline int query(int x,int l,int r)
{
    if(l<=tr[x].l&&tr[x].r<=r)
        return tr[x].val;
    int mid=tr[x].l+tr[x].r>>1;
    if(l>mid)return query(x<<1|1,l,r);
    else if(r<=mid)return query(x<<1,l,r);
    else return gcd(abs(a[mid]-a[mid+1]),gcd(query(x<<1,l,r),query(x<<1|1,l,r)));
}
inline void solve()
{
    cin>>n>>q;
    for(int i=1;i<=n;++i)cin>>a[i];
    build(1,1,n);
    while(q--)
    {
        cin>>l>>r;
        if(l==r){cout<<0<<' ';continue;}
        cout<<query(1,l,r)<<' ';
    }
    cout<<'\n';
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    cin>>T;
    while(T--)
    {
        solve();
    }
    return 0;
}

延伸

这让我想到了之前有一场 div2 的 A,就是给定一个 \(x,y\),然后求一个最小的 \(t\),使得\(t\mod x=t\mod y\),这种情况可以证明最小的能够找到的 \(m\) 一定是\(lcm(x,y)\)。这个其实画一下数轴就可以直观地感受出来了。

标签:return,gcd,int,times,问题,GCD,区间,同余
From: https://www.cnblogs.com/Hanggoash/p/18592418

相关文章

  • 内存问题案例:02 内存走线拓扑问题
    今天是内存问题案例第2篇:内存走线拓扑问题。01问题描述某主板使用DDR3表贴颗粒,X8颗粒正反贴,含ECC,TOP/BOTTOM面各9颗颗粒,每通道共18颗颗粒。实际测试发现内存速率只能到400Mbps,而另一个项目的单板内存速率可以到677Mbps。主板内存布局如下图所示,地址控制命令时钟信号的端接......
  • 信奥赛CSP-J复赛集训(dfs专题)(12):洛谷P2404:自然数的拆分问题
    信奥赛CSP-J复赛集训(dfs专题-刷题题单及题解)(12):洛谷P2404:自然数的拆分问题题目描述任何一个大于111的自然数n......
  • 大模型,多模态大模型面试问题【代码题,DDPM,损失函数,激活函数,3DGS,Nerf,SH】
    大模型,多模态大模型面试问题【代码题,DDPM,损失函数,激活函数,3DGS,Nerf,SH】代码题:1.区间最小数乘区间最大和的最大值算法:2.二叉树中的最大路径和问题一:DDPM加噪公式为什么是根号形式,时间步T为啥这么大,通常是1000。加噪公式的根号形式时间步......
  • Vue3 可访问性问题
    Vue3可访问性问题及解决方案引言随着前端技术的不断发展,用户体验已经成为衡量一个网站或应用成功与否的关键因素之一。尤其是在当今多元化的互联网环境中,确保所有用户都能访问和使用你的应用变得越来越重要。可访问性(Accessibility,简称A11Y)是指为所有人群(包括老年人、......
  • 鸿蒙技术分享:鸿蒙应用元服务上架审核拒审问题(持续更新@20241121)
    ......
  • 透彻理解并解决Mockito模拟框架的单元测试无法运行的问题
    本篇的实例基于MavenIDE(VSCode)运行在VSCode运行的时候,不需要在pom.xml中添加任何插件就可以在测试类中看到如下的绿色按钮,单击就可以运行使用Mockito注解@ExtendWith(MockitoExtension.class)或是Mockito代码方式的测试。不使用注解:***Copyright(C)......
  • UNIAPP小程序内Canvas下雪特效,解决蓝色雪花问题
      在小程序的开发中,如何为用户带来与众不同的体验一直是开发者关注的焦点。尤其是在冬季,给小程序加入一个浪漫的下雪特效,不仅能增强用户的互动体验,还能提升整体的应用氛围。今天,我们将介绍如何利用UNIAPP和Canvas技术,在小程序中实现一个炫酷的下雪特效。效果图......
  • 重链剖分, 树上路径问题大杀器
    重链剖分,树上路径问题大杀器首先,什么是树链剖分数组,要进行修改查询是非常方便的,一眼线段树.但是树并不是.看一下我们目前已有的树上修改查询技术.树上差分只能修改,最后才能查询,不然就只能很慢的单点查询,DFS序+线段树只能进行子树操作,不能进行路径操作.......
  • 解决流网络中不存在s~u~t路径的节点的最大流问题
    解决流网络中不存在s~u~t路径的节点的最大流问题问题分析伪代码C代码示例解释在流网络问题中,我们通常会假设对于所有的节点v∈V,都存在一条从源点s到汇点t经过v的路径。然而,当这一假设不成立时,即存在某些节点u,使得不存在路径sut,我们需要证明在这种情况下,网络中......
  • LVGL中roller滚动动画错乱的问题
    LVGL中roller滚动动画错乱的问题最近我在学习bilibili上一个博主的lvgl项目。在其中用到roller来制作一个时钟。我使用style将roller的动画时长拉长到500ms,此时问题出现。roller的内容有两种模式LV_ROLLER_MODE_NORMAL和LV_ROLLER_MODE_INFINITE。在普通模式下roller的滚动正常,但......