1 条题解

  • 0
    @ 2026-5-4 13:50:06

    首先我们可以发现 A 与 B 同时走一步相当于 A 走两步。假设这两步他选的是 c1c_1c2c_2,原来的位置为 xx,那么他会到达 2c2(2c1x)=2(c2c1)+x2c_2 - (2c_1 - x) = 2(c_2 - c_1) + x

    那么问题转化为是否存在一组解,使得有这样一个式子成立。

    2i=1k(1)ici=ba2\sum _{i = 1} ^ k (-1)^ic_i = b - a

    我们把它化成差分形式,把差分数组单独记为 did_i

    $$2\sum _ {i = 1} ^ k (c_{2i} - c_{2i - 1}) = 2\sum _{i=1}^k d_i = b - a$$

    不难发现,这个问题可以用裴蜀定理。具体地,可参考 this,可以得到有解当且仅当 2×gcd(d1,d2,,dk)ba2 \times \gcd (d_1, d_2, \cdots, d_k) \mid b - a

    那么这个问题就可以用二分解决了。具体的,我们可以将 aia_i 差分后按 ff 排序,然后我们对每个询问,二分 midmid 表示选 ffllmidmid 这段区间里的节点是否有解即可。

    再加上多组询问互相独立,可以用整体二分,再用线段树维护区间 gcd\gcd 即可。

    ::::info[Code]

    #include <bits/stdc++.h>
    using namespace std;
    
    bool st;
    
    const int N = 5e4 + 5;
    
    int n, m;
    
    struct Seg {
    	int tree[N << 2];
    	
    	void pushup (int node) { tree[node] = __gcd (tree[node << 1], tree[(node << 1) + 1]); }
    	
    	void modify (int node, int l, int r, int s, int c) {
    		if (l == r) {
    			tree[node] = c;
    			return ;
    		}
    		
    		int mid = l + ((r - l) >> 1);
    		if (s <= mid) modify (node << 1, l, mid, s, c);
    		else modify ((node << 1) + 1, mid + 1, r, s, c);
    		pushup (node);
    	}
    	
    	int query (int node, int l, int r, int s, int t) {
    		if (s <= l && r <= t) return tree[node];
    		
    		int mid = l + ((r - l) >> 1), ret = 0;
    		if (s <= mid) ret = __gcd (ret, query (node << 1, l, mid, s, t));
    		if (t > mid) ret = __gcd (ret, query ((node << 1) + 1, mid + 1, r, s, t));
    		return ret;
    	}
    } T; 
    
    struct node {
    	int id, c, f;
    	bool operator < (const node &T) const { return f < T.f; }
    } a[N], b[N];
    
    struct Query {
    	int id, l, r, a, b;
    } q[N], q1[N], q2[N];
    int ans[N];
    
    void solve (int l, int r, int L, int R) {
    	if (L == R) {
    		T.modify (1, 1, n, b[L].id, b[L].c);
    		for (int i = l; i <= r; ++i) {
    			long long tmp = 2 * T.query (1, 1, n, q[i].l, q[i].r);
    			// 判无解记得判 gcd != 0 
    			if (!tmp || (q[i].b - q[i].a) % tmp) ans[q[i].id] = -1;
    			else ans[q[i].id] = b[L].f;
    		}
    		T.modify (1, 1, n, b[L].id, 0);
    		return ;
    	}
    	
    	int mid = L + ((R - L) >> 1), cnt1 = 0, cnt2 = 0;
    	for (int i = L; i <= mid; ++i) T.modify (1, 1, n, b[i].id, b[i].c);
    	for (int i = l; i <= r; ++i) {
    		long long tmp = 2 * T.query (1, 1, n, q[i].l, q[i].r);
    		if (!tmp || (q[i].b - q[i].a) % tmp) q2[++cnt2] = q[i];
    		else q1[++cnt1] = q[i];
    	} 
    	
    	for (int i = 1; i <= cnt1; ++i) q[l + i - 1] = q1[i];
    	for (int i = 1; i <= cnt2; ++i) q[l + cnt1 + i - 1] = q2[i];
    	solve (l + cnt1, r, mid + 1, R);
    	for (int i = L; i <= mid; ++i) T.modify (1, 1, n, b[i].id, 0);
    	solve (l, l + cnt1 - 1, L, mid);
    }
    
    bool ed;
    
    int main () {
    
    	ios::sync_with_stdio (false);
    	cin.tie (0); cout.tie (0);
    	
    	cerr << "[Memory] " << (&st - &ed) / 1024 / 1024 << " MB\n";
    	
    	cin >> n >> m;
    	for (int i = 1; i <= n; ++i) cin >> a[i].c;
    	for (int i = 1; i <= n; ++i) cin >> a[i].f;
    	sort (a + 1, a + n + 1);
    	for (int i = 1; i < n; ++i) b[i] = {i + 1, a[i + 1].c - a[i].c, a[i + 1].f - a[i].f};
    	sort (b + 1, b + n);
    	
    	for (int i = 1; i <= m; ++i) {
    		cin >> q[i].a >> q[i].b >> q[i].l >> q[i].r;
    		q[i].id = i;
    		q[i].l = lower_bound (a + 1, a + n + 1, (node){0, 0, q[i].l}) - a + 1;
    		q[i].r = upper_bound (a + 1, a + n + 1, (node){0, 0, q[i].r}) - a - 1;
    		if (q[i].l > q[i].r) ans[i] = -1;
    	}
    	
    	solve (1, m, 1, n - 1);
    	for (int i = 1; i <= m; ++i) cout << ans[i] << ' '; 
    	return 0;
    }
    

    ::::

    • 1

    信息

    ID
    7314
    时间
    1000ms
    内存
    512MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者