ABC254 F - Rectangle GCD( 数据结构&&gcd)

题目

传送门

题意:

给你两个数组 A , B A,B A,B
生成一个矩阵:位置 ( i , j ) (i,j) (i,j)的值为 A i + B j A_i+B_j Ai+Bj

询问q次,每次询问一个子矩阵的gcd。

思路:

step1:

弱化下问题:假如是询问q次区间gcd?
那么我们可以考虑用线段树优化或者rmq

step2:

  • 先看一行的计算结果:
    g c d ( A x 1 + B y 1 , A x 1 + B y 1 + 1 , . . . , A x 1 + B y 2 ) gcd(A_{x_1} + B_{y_1},A_{x_1} + B_{y_1+1},...,A_{x_1} + B_{y_2}) gcd(Ax1+By1,Ax1+By1+1,...,Ax1+By2)
    根据差分,转换为
    g c d ( A x 1 + B y 1 , B y 1 + 1 − B y 1 , . . . , B y 2 − B y 2 − 1 ) gcd(A_{x_1} + B_{y_1}, B_{y_1+1} - B_{y_1},..., B_{y_2} - B_{y_2-1}) gcd(Ax1+By1,By1+1By1,...,By2By21)

我们发现根据step1,我们可以快速计算出一行的结果。

  • 看多行的结果:

g c d ( A x 1 + B y 1 , A x 1 + B y 1 + 1 , . . . , A x 1 + B y 2 ) gcd(A_{x_1} + B_{y_1},A_{x_1} + B_{y_1+1},...,A_{x_1} + B_{y_2}) gcd(Ax1+By1,Ax1+By1+1,...,Ax1+By2)
g c d ( A x 1 + 1 + B y 1 , A x 1 + 1 + B y 1 + 1 , . . . , A x 1 + 1 + B y 2 ) gcd(A_{x_1+1} + B_{y_1},A_{x_1+1} + B_{y_1+1},...,A_{x_1+1} + B_{y_2}) gcd(Ax1+1+By1,Ax1+1+By1+1,...,Ax1+1+By2)

g c d ( A x 2 + B y 1 , A x 2 + B y 1 + 1 , . . . , A x 2 + B y 2 ) gcd(A_{x_2} + B_{y_1},A_{x_2} + B_{y_1+1},...,A_{x_2} + B_{y_2}) gcd(Ax2+By1,Ax2+By1+1,...,Ax2+By2)

根据差分,转换为

g c d ( A x 1 + B y 1 , B y 1 + 1 − B y 1 , . . . , B y 2 − B y 2 − 1 ) gcd(A_{x_1} + B_{y_1}, B_{y_1+1} - B_{y_1},..., B_{y_2} - B_{y_2-1}) gcd(Ax1+By1,By1+1By1,...,By2By21)

g c d ( A x 1 + 1 + B y 1 , B y 1 + 1 − B y 1 , . . . , B y 2 − B y 2 − 1 ) gcd(A_{x_1 + 1} + B_{y_1}, B_{y_1+1} - B_{y_1},..., B_{y_2} - B_{y_2-1}) gcd(Ax1+1+By1,By1+1By1,...,By2By21)

g c d ( A x 2 + B y 1 , B y 1 + 1 − B y 1 , . . . , B y 2 − B y 2 − 1 ) gcd(A_{x_2} + B_{y_1}, B_{y_1+1} - B_{y_1},..., B_{y_2} - B_{y_2-1}) gcd(Ax2+By1,By1+1By1,...,By2By21)

我们会发现除了第一列以外,其他列的值一样,所以我们可以直接求出后面的gcd。
而第一列的gcd也可以快速根据step1维护。

step3:

板子的gcd可能会因为负数wa

AC

#include <iostream>
#include <cstdio>
#include <vector>
#include <map>
#include <unordered_map>
#include <set>
#include <algorithm>
#include <bits/stdc++.h>
#include <queue>
#include <stack>
#include <string>
#include <cmath>
#include <cstring>
#define For(i,x,y) for(int i = (x); i <= (y); i ++ )
#define fori(i,x,y) for(int i = (x); i < (y); i ++ )
#define sz(a) (int)a.size()
#define ALL(a) a.begin(), a.end()
#define mst(x,a) memset(x,a,sizeof(x))
#define pb push_back
#define eb emplace_back
#define mp make_pair
#define fi first
#define se second
#define db double
#define endl '\n' 
#define debug(a) cout << #a << ": " << a << endl
using namespace std;
typedef long long LL;
typedef long long ll;
typedef unsigned long long ULL;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
typedef pair<int,int>pa;
typedef pair<ll,ll>pai;
typedef pair<db,db> pdd;
const db eps = 1e-6;
const db pi = acos(-1.0);

template<typename T1, typename T2> void ckmin(T1 &a, T2 b) { if (a > b) a = b; }
template<typename T1, typename T2> void ckmax(T1 &a, T2 b) { if (a < b) a = b; }
int read() {
    int x = 0, f = 0; char ch = getchar();
    while (!isdigit(ch)) f |= ch == '-', ch = getchar();
    while (isdigit(ch)) x = 10 * x + ch - '0', ch = getchar();
    return f ? -x : x;
}
template<typename T> void print(T x) {
    if (x < 0) putchar('-'), x = -x;
    if (x >= 10) print(x / 10);
    putchar(x % 10 + '0');
}
template<typename T> void print(T x, char let) {
    print(x), putchar(let);
}
template<class T> bool uin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool uax(T &a, T b) { return a < b ? (a = b, true) : false; }

const int maxn = 200000 + 6;
const int LOGMX = 20;
int gcd(int a, int b) {
    if(b == 0) return a;
    return gcd(b,a%b);
}
int a[maxn], b[maxn];
int c[maxn][LOGMX], d[maxn][LOGMX];
int logn[maxn];
void init(){
    for(int i = 2; i < maxn; i ++ ) logn[i] = logn[i/2] + 1;
}
int query1(int l, int r) {
    if(l > r) return 0;
    int s = logn[r-l+1];
    return std::gcd(c[l][s],c[r-(1<<s)+1][s]);
}
int query2(int l, int r) {
    if(l > r) return 0;
    int s = logn[r-l+1];
    return std::gcd(d[l][s],d[r-(1<<s)+1][s]);
}
int main() {
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    // gcd(a1+b1,a1+b2,a1+b3);
    // gcd(a1+b1,b2-b1,b3-b1)
    init();
    int n, q;
    cin >> n >> q;
    for(int i = 1; i <= n; i ++ ) cin >> a[i];
    for(int i = 1; i <= n; i ++ ) cin >> b[i];


    for(int i = 1; i < n; i ++ ) {
        c[i][0] = a[i+1] - a[i];
        d[i][0] = b[i+1] - b[i];
    }

    //rmq init
    for(int j = 1; j < LOGMX; j ++ ) {
        for(int i = 1; i + (1<<j) - 1 < n; i ++) {
            c[i][j] = std::gcd(c[i][j-1], c[i+(1<<(j-1))][j-1]);
            d[i][j] = std::gcd(d[i][j-1], d[i+(1<<(j-1))][j-1]);
        }
    }

    for(int i = 1; i <= q; i ++ ) {
        int x1,y1,x2,y2;
        cin>> x1 >> x2 >> y1 >> y2;
        cout << std::gcd(a[x1] + b[y1], gcd(query1(x1,x2-1), query2(y1,y2-1))) << endl;
    }

    return 0;
}
//负数的gcd,和推导
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值