• 【裴蜀定理】CF1055C Lucky Days


    Lucky Days

    较好观感

    给定 l a , r a , t a , l b , r b , t b l_a,r_a,t_a,l_b,r_b,t_b la,ra,ta,lb,rb,tb,对于所有的非负整数 k k k,将区间 [ l a + k t a , r a + k t a ] [l_a+kt_a,r_a+kt_a] [la+kta,ra+kta] 打上标记 1 1 1,将区间 [ l b + k t b , r b + k t b ] [l_b+kt_b,r_b+kt_b] [lb+ktb,rb+ktb] 打上标记 2 2 2。求出最长的连续区间使得该区间中的所有位置都被同时打上的 1 , 2 1,2 1,2 标记。

    样例一

    0 2 5
    1 3 5
    
    • 1
    • 2
    2
    
    • 1

    样例二

    0 1 3
    2 3 6
    
    • 1
    • 2
    1
    
    • 1

    样例一

    样例二


    思路

    题目要求两个区间的重合度最大的长度。

    首先第一个点我们要想到:要想使两个区间的重合度最高,需要让两个区间尽可能逼近。最优的情况就是两个区间的左端点尽可能相等,这样重合度是最大的。

    即使 l a + x ∗ t a = l b + y ∗ t b la + x * ta = lb + y * tb la+xta=lb+ytb

    将式子进行移项得 x ∗ t a − y ∗ t b = l b − l a x * ta - y * tb = lb - la xtaytb=lbla (此时我们假设 l a < l b la < lb la<lb,代码中已做相关的操作,这样只是为了方便)

    我们需要看式子是否有解,式子结构和裴蜀定理比较像,拿出来进行对比。

    裴蜀定理 : 存在整数 x , y x, y x,y,满足 a ∗ x + b ∗ y = g c d ( a , b ) a * x + b * y = gcd(a,b) ax+by=gcd(a,b)

    该式子进行 y y y符号变为正,表示 y y y是整数,则 x ∗ t a + y ∗ t b = l b − l a x * ta + y * tb = lb - la xta+ytb=lbla

    我们令 d = g c d ( t a , t b ) d = gcd(ta, tb) d=gcd(ta,tb)

    那么可以发现如果 d ∣ ( l b − l a ) d | (lb - la) d(lbla),则该式子有解,左端点可以重合。


    但是如果左端点不能重合怎么办,尽可能逼近就行。

    此时别忘了式子右边的 l b − l a lb-la lbla代表的是什么,是 区间a左端点移动的距离,那么因为 x ∗ t a + y ∗ t b = d x * ta + y * tb = d xta+ytb=d是存在解的,则区间a移动的距离可进一步变为 d d d

    注意:我说的区间a可以移动,是指的一定存在某种状态,上下两个人有两个区间的距离发生了变化,叫为区间移动更容易理解。如

    t a = 3 , [ 1 , 4 ] − > [ 4 , 7 ] − > [ 7 , 10 ] − > [ 10 , 13 ] ta = 3,[1,4]->[4,7]->[7,10]->[10,13] ta=3,[1,4]>[4,7]>[7,10]>[10,13]

    t b = 4 , [ 3 , 5 ] − > [ 7 , 9 ] − > [ 11 , 13 ] tb = 4,[3,5]->[7,9]->[11,13] tb=4,[3,5]>[7,9]>[11,13]

    [ 1 , 4 ] [ 3 , 5 ] [1,4][3,5] [1,4][3,5]左端点相差 2 2 2,这是一种区间状态,通过移动,会出现另一种区间状态 [ 10 , 13 ] [ 11 , 13 ] [10,13][11,13] [10,13][11,13]左端点相差 1 1 1。移动了一步( d = g c d ( 3 , 4 ) = 1 d = gcd(3,4) = 1 d=gcd(3,4)=1

    左端点不重合就尽可能逼近。

    有两种状态可能是合适的。

    d i s dis dis代表a区间左端点与b区间左端点相差的最小距离(a区间左端点我认为小于等于b区间左端点),即 d i s = ( l b − l a ) % d dis = (lb - la) \% d dis=(lbla)%d

    • 区间a左端点移动到和区间b左端点相差 ( l b − l a ) % d (lb-la) \% d (lbla)%d,可能是距离最近的

      • m i n ( r b − l b + 1 , r a − l a + 1 − d i s ) min(rb - lb + 1, ra - la + 1 - dis) min(rblb+1,rala+1dis)
    • 然后是上面的情况在往后移一步,即区间a左端点超过区间b左端点 d − ( l b − l a ) d-(lb-la)%d d(lbla)

      • d i s = d − d i s dis = d - dis dis=ddis
      • m i n ( r a − l a + 1 , r b − l b + 1 − d i s ) min(ra - la + 1, rb - lb + 1 - dis) min(rala+1,rblb+1dis)

    两个计算请画图领悟计算方法。

    计算:左端点重合的情况可以合并在左端点能合并的代码里面,即左端点合并是左端点不合并的特殊情况。

    代码

    #include
    using namespace std;
    using ll = long long;
    using pii = pair<int, int>;
    const int N = 1e5 + 5, mod = 1e9 + 7;
    
    // [l[a] + k * ta, r[a] + k * ta]
    // 3 [1, 4] [4, 7] [7, 10] [10, 13] [13, 16] ---
    // 4 [3, 5] [7, 9] [11, 13]         [15, 17] ---
    // 起点尽可能相同
    // 裴蜀定理:存在x,y 使 ax + by = gcd(a, b)
    // la + x * ta = lb + y * tb
    // x * ta - y * tb = lb - la
    // gcd(ta, tb) | (lb - la)有解
    // d = gcd(ta, tb) 看成相对移动的距离
    // la -> la + d -> la + k * d    lb
    // 差 = lb - la 
    // dis = (lb - la) % d
    
    void solve()
    {
    	int la, ra, ta, lb, rb, tb;
    	cin >> la >> ra >> ta >> lb >> rb >> tb;
    	if(la > lb)
    	{
    		swap(la, lb);
    		swap(ra, rb);
    		swap(ta, tb);
    	}
    	int d = __gcd(ta, tb);
    	int dis = (lb - la) % d; // 左端点的差
    	int ans = 0;
    	ans = max(ans, min(rb - lb + 1, ra - la + 1 - dis));
    	dis = d - dis; // 向右移动一步
    	ans = max(ans, min(ra - la + 1, rb - lb + 1 - dis));
    	cout << ans << "\n";
    }
    int main()
    {
    	ios::sync_with_stdio(false);
    	cin.tie(0);
    
    	int t;
    	// cin >> t;
    	t = 1;
    	while(t--)
    		solve();
    	return 0;
    }
    
    • 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
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
  • 相关阅读:
    美容行业怎样利用自动化程序减少积压索赔案件
    C语言工具——Visual Studio 的安装
    2024年航空安全员考试题库及答案
    SpringCash
    C#程序发布时,一定要好好地保护,不然你会后悔的
    ZooKeeper(一):基础介绍
    Leetcode 340. 至多包含 K 个不同字符的最长子串(滑动窗口)
    mysql 中查看某个库中所有包含某个字段的表
    Java性能优化的过程方法与求职面经总结
    从北京到南京:偶数在能源行业的数据迁移实践
  • 原文地址:https://blog.csdn.net/qq_50285142/article/details/126235428