Lucky Days
给定 ,对于所有的非负整数 ,将区间 打上标记 ,将区间 打上标记 。求出最长的连续区间使得该区间中的所有位置都被同时打上的 标记。
样例一
0 2 5
1 3 5
2
样例二
0 1 3
2 3 6
1
思路
题目要求两个区间的重合度最大的长度。
首先第一个点我们要想到:要想使两个区间的重合度最高,需要让两个区间尽可能逼近。最优的情况就是两个区间的左端点尽可能相等,这样重合度是最大的。
即使
将式子进行移项得 (此时我们假设,代码中已做相关的操作,这样只是为了方便)
我们需要看式子是否有解,式子结构和裴蜀定理比较像,拿出来进行对比。
裴蜀定理 : 存在整数 ,满足
该式子进行符号变为正,表示是整数,则
我们令
那么可以发现如果,则该式子有解,左端点可以重合。
但是如果左端点不能重合怎么办,尽可能逼近就行。
此时别忘了式子右边的代表的是什么,是 区间a左端点移动的距离,那么因为是存在解的,则区间a移动的距离可进一步变为 。
注意:我说的区间a可以移动,是指的一定存在某种状态,上下两个人有两个区间的距离发生了变化,叫为区间移动更容易理解。如
左端点相差,这是一种区间状态,通过移动,会出现另一种区间状态左端点相差。移动了一步()
左端点不重合就尽可能逼近。
有两种状态可能是合适的。
代表a区间左端点与b区间左端点相差的最小距离(a区间左端点我认为小于等于b区间左端点),即
-
区间a左端点移动到和区间b左端点相差,可能是距离最近的
-
然后是上面的情况在往后移一步,即区间a左端点超过区间b左端点
两个计算请画图领悟计算方法。
计算:左端点重合的情况可以合并在左端点能合并的代码里面,即左端点合并是左端点不合并的特殊情况。
代码
#include<bits/stdc++.h>
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;
}