B - GCD Subtraction
题意:
给定两个正整数 A , B A,B A,B,给定一个操作:令 g = g c d ( A , B ) g=gcd(A, B) g=gcd(A,B),令 A = A − g , B = B − g A=A-g, B=B-g A=A−g,B=B−g。问最少经过多少次操作之后其中一个数变为0.
思路:
令 
     
      
       
        
        
          A 
         
        
          ′ 
         
        
       
         = 
        
       
         A 
        
       
         / 
        
       
         g 
        
       
         , 
        
        
        
          B 
         
        
          ′ 
         
        
       
         = 
        
       
         B 
        
       
         / 
        
       
         g 
        
       
      
        A'=A/g,B'=B/g 
       
      
    A′=A/g,B′=B/g,操作一次后等价于求 
     
      
       
       
         ( 
        
        
        
          A 
         
        
          ′ 
         
        
       
         − 
        
       
         1 
        
       
         ) 
        
       
         ∗ 
        
       
         g 
        
       
         , 
        
       
         ( 
        
        
        
          B 
         
        
          ′ 
         
        
       
         − 
        
       
         1 
        
       
         ) 
        
       
         ∗ 
        
       
         g 
        
       
      
        (A'-1)*g,(B'-1)*g 
       
      
    (A′−1)∗g,(B′−1)∗g的答案。而且不难发现的是,后面的 
     
      
       
       
         g 
        
       
      
        g 
       
      
    g对答案并无影响,所以等价于求 
     
      
       
        
        
          A 
         
        
          ′ 
         
        
       
         − 
        
       
         1 
        
       
         , 
        
        
        
          B 
         
        
          ′ 
         
        
       
         − 
        
       
         1 
        
       
      
        A'-1,B'-1 
       
      
    A′−1,B′−1的答案。
 显然,如果 
     
      
       
       
         g 
        
       
         > 
        
       
         1 
        
       
      
        g>1 
       
      
    g>1那么该操作最多进行 
     
      
       
       
         l 
        
       
         o 
        
       
         g 
        
       
      
        log 
       
      
    log次,直接暴力递归求解即可。如果 
     
      
       
       
         g 
        
       
         = 
        
       
         1 
        
       
      
        g=1 
       
      
    g=1,那么我们需要找到一个最小的整数 
     
      
       
       
         x 
        
       
      
        x 
       
      
    x,使得 
     
      
       
       
         g 
        
       
         c 
        
       
         d 
        
       
         ( 
        
        
        
          A 
         
        
          ′ 
         
        
       
         − 
        
       
         1 
        
       
         − 
        
       
         x 
        
       
         , 
        
       
         B 
        
       
         − 
        
       
         1 
        
       
         − 
        
       
         x 
        
       
         ) 
        
       
         ≠ 
        
       
         1 
        
       
      
        gcd(A'-1-x,B-1-x)\neq1 
       
      
    gcd(A′−1−x,B−1−x)=1。即满足 
     
      
       
       
         A 
        
       
         ≡ 
        
       
         B 
        
       
         ( 
        
       
         m 
        
       
         o 
        
       
         d 
        
       
         m 
        
       
         ) 
        
       
      
        A\equiv B(mod m) 
       
      
    A≡B(modm)。我们令 
     
      
       
       
         A 
        
       
         = 
        
        
        
          k 
         
        
          1 
         
        
       
         ∗ 
        
       
         m 
        
       
         + 
        
        
        
          b 
         
        
          1 
         
        
       
         , 
        
       
         B 
        
       
         = 
        
        
        
          k 
         
        
          2 
         
        
       
         ∗ 
        
       
         m 
        
       
         + 
        
        
        
          b 
         
        
          1 
         
        
       
      
        A=k_1*m+b_1,B=k_2*m+b_1 
       
      
    A=k1∗m+b1,B=k2∗m+b1,我们要找最小的 
     
      
       
        
        
          b 
         
        
          1 
         
        
       
      
        b_1 
       
      
    b1。 
     
      
       
       
         A 
        
       
         − 
        
       
         B 
        
       
      
        A-B 
       
      
    A−B也是 
     
      
       
       
         m 
        
       
      
        m 
       
      
    m的倍数,那么我们暴力枚举 
     
      
       
       
         A 
        
       
         − 
        
       
         B 
        
       
      
        A-B 
       
      
    A−B的因数即可。时间复杂度 
     
      
       
        
        
          n 
         
        
       
         ∗ 
        
       
         l 
        
       
         o 
        
       
         g 
        
       
         n 
        
       
      
        \sqrt{n}*logn 
       
      
    n∗logn
代码:
LL a, b, ans;
 
void solve(LL x) {
    LL t = b;
    for(LL i = 2; i * i <= x; i++) {
        if(x % i == 0) {
            if(a % i == b % i) t = min(t, a % i);
            if(a % (x / i) == b % (x / i)) t = min(t, a % (x / i));
        }
    }
    if(a % x == b % x) t = min(t, a % x);
    ans += t;
    a -= t;
    b -= t;
}
 
int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
 
    cin >> a >> b;
    while(a && b) {
        if(a < b) swap(a, b);
        LL g = __gcd(a, b);
        a /= g, b /= g;
        a--, b--;
        ans++;
        if(a == 0 || b == 0) break;
 
        if(a - 1 == b) {
            ans += b;
            break;
        }
        if(a == b) {
            ans++;
            break;
        }
        solve(a - b);
    }
    cout << ans << '\n';
 
	return 0;
}
C - Permutation Addition
题意:
给定一个长为 n , n ≤ 50 n,n\leq 50 n,n≤50的数组 a [ i ] a[i] a[i],每次可以选择一个 n n n的排列 p p p,使得 a [ i ] = a [ i ] + p [ i ] a[i]=a[i]+p[i] a[i]=a[i]+p[i],求能否在操作次数不超过 1 e 4 1e4 1e4的前提下将数组所有元素变得相等。
思路:
对于这种限制操作次数,而且很明显操作次数会很多的构造题,我们应尽量去找存不存在一个元操作使数组有某种变化,然后复制该操作。
 我们令 
     
      
       
       
         s 
        
       
         u 
        
       
         m 
        
       
         = 
        
       
         ∑ 
        
        
        
          a 
         
        
          [ 
         
        
          i 
         
        
          ] 
         
        
       
      
        sum=\sum{a[i]} 
       
      
    sum=∑a[i],显然最后要使 
     
      
       
       
         s 
        
       
         u 
        
       
         m 
        
       
         % 
        
       
         n 
        
       
         = 
        
       
         0 
        
       
      
        sum\%n=0 
       
      
    sum%n=0。
 若 
     
      
       
       
         n 
        
       
      
        n 
       
      
    n为奇数,则 
     
      
       
        
         
         
           n 
          
         
           ∗ 
          
         
           ( 
          
         
           n 
          
         
           + 
          
         
           1 
          
         
           ) 
          
         
        
          2 
         
        
       
         % 
        
       
         n 
        
       
         = 
        
       
         0 
        
       
      
        \frac{n*(n+1)}{2}\%n=0 
       
      
    2n∗(n+1)%n=0, 
     
      
       
       
         s 
        
       
         u 
        
       
         m 
        
       
         % 
        
       
         n 
        
       
         = 
        
       
         0 
        
       
      
        sum\%n=0 
       
      
    sum%n=0有解,我们构造两个排列: 
     
      
       
       
         n 
        
       
         = 
        
       
         5 
        
       
      
        n=5 
       
      
    n=5:
  
     
      
       
       
         p 
        
       
         : 
        
       
         1 
        
        
       
         2 
        
        
       
         3 
        
        
       
         4 
        
       
         , 
        
        
        
          p 
         
        
          ′ 
         
        
       
         : 
        
       
         4 
        
        
       
         3 
        
        
       
         2 
        
        
       
         1 
        
       
      
        p:1\quad 2 \quad 3 \quad 4, p':4\quad 3\quad 2\quad 1 
       
      
    p:1234,p′:4321。之后相当于 
     
      
       
       
         a 
        
       
         [ 
        
       
         1 
        
       
         ] 
        
       
         + 
        
       
         1 
        
       
         , 
        
       
         a 
        
       
         [ 
        
       
         2 
        
       
         ] 
        
       
         − 
        
       
         1 
        
       
      
        a[1]+1,a[2]-1 
       
      
    a[1]+1,a[2]−1。那么我们就找到了一个元操作,使得一个位置增加1,一个位置减少1.
 若 
     
      
       
       
         n 
        
       
      
        n 
       
      
    n为偶数,则 
     
      
       
        
         
         
           n 
          
         
           ∗ 
          
         
           ( 
          
         
           n 
          
         
           + 
          
         
           1 
          
         
           ) 
          
         
        
          2 
         
        
       
         % 
        
       
         n 
        
       
         = 
        
        
        
          n 
         
        
          2 
         
        
       
      
        \frac{n*(n+1)}{2}\%n=\frac{n}{2} 
       
      
    2n∗(n+1)%n=2n,则 
     
      
       
       
         s 
        
       
         u 
        
       
         m 
        
       
         % 
        
       
         n 
        
       
         = 
        
       
         0 
        
       
         , 
        
       
         s 
        
       
         u 
        
       
         m 
        
       
         % 
        
       
         n 
        
       
         = 
        
        
        
          n 
         
        
          2 
         
        
       
      
        sum\%n=0,sum\%n=\frac{n}{2} 
       
      
    sum%n=0,sum%n=2n有解。
 对于 
     
      
       
       
         s 
        
       
         u 
        
       
         m 
        
       
         % 
        
       
         n 
        
       
         = 
        
       
         n 
        
       
         / 
        
       
         2 
        
       
      
        sum\%n=n/2 
       
      
    sum%n=n/2,我们先随便找一个排列将其变成 
     
      
       
       
         s 
        
       
         u 
        
       
         m 
        
       
         % 
        
       
         n 
        
       
         = 
        
       
         0 
        
       
      
        sum\%n=0 
       
      
    sum%n=0即可。
代码:
int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
 
    int n;
    cin >> n;
    vector<int> a(n + 1);
    int sum = 0;
    for(int i = 1; i <= n; i++) {
        cin >> a[i];
        sum += a[i];
    }
    if(n % 2 == 0 && sum % n != 0 && sum % n != n / 2) {
        cout << "No\n";
        return 0;
    }
    if(n % 2 && sum % n != 0) {
        cout << "No\n";
        return 0;
    }
    cout << "Yes\n";
    int f = 0;
    if(n % 2 == 0 && sum % n == n / 2) {
        f = 1;
        sum += n * (n + 1) / 2;
        for(int i = 1; i <= n; i++) a[i] += i;
    }   
    vector<int> x, y;
    int mid = sum / n;
    for(int i = 1; i <= n; i++) {
        while(a[i] < mid) x.pb(i), a[i]++;
        while(a[i] > mid) y.pb(i), a[i]--;
    }
    cout << SZ(x) * 2 + f << '\n';
    if(f) {
        for(int i = 1; i <= n; i++) cout << i << " \n"[i == n];
    }
    for(int i = 0; i < SZ(x); i++) {
        int l = 2, r = n - 1;
        for(int j = 1; j <= n; j++) {
            cout << (j != x[i] && j != y[i] ? ++l : (j == x[i] ? 2 : 1)) << " \n"[j == n];
        }
        for(int j = 1; j <= n; j++) {
            cout << (j != x[i] && j != y[i] ? --r : (j == x[i] ? n : n - 1)) << " \n"[j == n];            
        }
    }
    
 
	return 0;
}
D - LIS 2
题意:

思路:
一个很重要的性质:若一个区间被选,那么选的一定是其一个后缀。
 所以我们定义 
     
      
       
       
         d 
        
       
         p 
        
       
         [ 
        
       
         i 
        
       
         ] 
        
       
      
        dp[i] 
       
      
    dp[i]:第i个区间必选的最长上升子序列。
 转移:
 若区间 
     
      
       
       
         j 
        
       
         , 
        
       
         r 
        
       
         [ 
        
       
         j 
        
       
         ] 
        
       
         < 
        
       
         l 
        
       
         [ 
        
       
         i 
        
       
         ] 
        
       
      
        j,r[j]<l[i] 
       
      
    j,r[j]<l[i],那么 
     
      
       
       
         f 
        
       
         [ 
        
       
         i 
        
       
         ] 
        
       
         = 
        
       
         m 
        
       
         a 
        
       
         x 
        
       
         ( 
        
       
         f 
        
       
         [ 
        
       
         j 
        
       
         ] 
        
       
         + 
        
       
         r 
        
       
         [ 
        
       
         i 
        
       
         ] 
        
       
         − 
        
       
         l 
        
       
         [ 
        
       
         i 
        
       
         ] 
        
       
         + 
        
       
         1 
        
       
         ) 
        
       
      
        f[i]=max(f[j]+r[i]-l[i]+1) 
       
      
    f[i]=max(f[j]+r[i]−l[i]+1)
 若区间 
     
      
       
       
         j 
        
       
         , 
        
       
         r 
        
       
         [ 
        
       
         j 
        
       
         ] 
        
       
         ≥ 
        
       
         l 
        
       
         [ 
        
       
         i 
        
       
         ] 
        
       
      
        j,r[j]\geq l[i] 
       
      
    j,r[j]≥l[i],那么 
     
      
       
       
         f 
        
       
         [ 
        
       
         i 
        
       
         ] 
        
       
         = 
        
       
         m 
        
       
         a 
        
       
         x 
        
       
         ( 
        
       
         f 
        
       
         [ 
        
       
         j 
        
       
         ] 
        
       
         + 
        
       
         r 
        
       
         [ 
        
       
         i 
        
       
         ] 
        
       
         − 
        
       
         r 
        
       
         [ 
        
       
         j 
        
       
         ] 
        
       
         ) 
        
       
      
        f[i]=max(f[j]+r[i]-r[j]) 
       
      
    f[i]=max(f[j]+r[i]−r[j])
 那么我们将其离散化后建两颗线段树分别维护 
     
      
       
       
         f 
        
       
         [ 
        
       
         j 
        
       
         ] 
        
       
         , 
        
       
         f 
        
       
         [ 
        
       
         j 
        
       
         ] 
        
       
         − 
        
       
         r 
        
       
         [ 
        
       
         j 
        
       
         ] 
        
       
      
        f[j],f[j]-r[j] 
       
      
    f[j],f[j]−r[j]即可。
代码:
#define int LL
int lsh[N], a[N], n;
int l[N], r[N];
int ll[N], rr[N];
 
struct Node {
    int tr[N * 4];
    void pushup(int u) {
        tr[u] = max(tr[lson], tr[rson]);
    }
    void modify(int u, int l, int r, int pos, int val) {
        if(l == r && l == pos) {
            tr[u] = max(tr[u], val);
            return;
        }
        int mid = l + r >> 1;
        if(pos <= mid) modify(lson, l, mid, pos, val);
        else modify(rson, mid + 1, r, pos, val);
        pushup(u);
    }
    int query(int u, int l, int r, int L, int R) {
        // return 0;
        // cout << u << ' ';
        if(L <= l && r <= R) {
            return tr[u];
        }
        int mid = l + r >> 1;
        int res = -INF;
        if(L <= mid) res = max(res, query(lson, l, mid, L, R));
        if(R > mid) res = max(res, query(rson, mid + 1, r, L, R));
        return res;
    }
}seg1, seg2;
int dp[N];
 
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
 
    memset(seg1.tr, -0x3f, sizeof seg1.tr);
    memset(seg2.tr, -0x3f, sizeof seg2.tr);
    cin >> n;
    int id = 0;
    for(int i = 1; i <= n; i++) {
        cin >> l[i] >> r[i];
        lsh[++id] = l[i],
        lsh[++id] = r[i];
    }
    sort(lsh + 1, lsh + 1 + id);
    id = unique(lsh + 1, lsh + 1 + id) - lsh - 1;
    for(int i = 1; i <= n; i++) {
        ll[i] = lower_bound(lsh + 1, lsh + 1 + id, l[i]) - lsh;
        rr[i] = lower_bound(lsh + 1, lsh + 1 + id, r[i]) - lsh;
        // DD(ll[i], rr[i])
    }
    dp[0] = 0;
    seg1.modify(1, 0, 2 * n, 0, 0);
    seg2.modify(1, 0, 2 * n, 0, 0);
    for(int i = 1; i <= n; i++) {
        dp[i] = max(dp[i], seg1.query(1, 0, 2 * n, 0, ll[i] - 1) + r[i] - l[i] + 1);
        dp[i] = max(dp[i], seg2.query(1, 0, 2 * n, ll[i], rr[i]) + r[i]);
        // D(dp[i])
        // DD(seg2.tr[5], seg2.tr[6])
        seg1.modify(1, 0, n * 2, rr[i], dp[i]);
        seg2.modify(1, 0, n * 2, rr[i], dp[i] - r[i]);
    }
    LL ans = *max_element(dp + 1, dp + 1 + n);
    cout << ans;
 
	return 0;
}

![[LeetCode周赛复盘] 第 354 场周赛20230716](https://img-blog.csdnimg.cn/2d91ffbf611d424d9131cd29deea6e47.png)

















