• CF623B Array GCD


    CF623B Array GCD

    给定一个序列 (a_i) ,可以进行一下两种操作:

    • 删除一段长度为 (m) 的区间 ((m<n)) ,花费为 (m imes A) ,只能操作一次
    • 可以花费 (b) 让一个元素 (+1)(-1) ,每个元素只能操作一次

    求使得剩下的数最大公约数大于 (1) 的最小花费

    (nleq10^6, a_{i}in[2, 10^9])

    贪心,动态规划


    由于删除的区间长度小于 (n) ,则最优解剩下的序列一定包含 (a_1)(a_n) ,则最后的 (gcd) 一定是 (a_1, a_1+1, a_1-1, a_n, a_n+1, a_n-1) 其中之一的约数

    由于每个数的不同质因子个数是 (log) 级别的,可以考虑枚举这 (6) 个数各自的质因子当作最大公约数

    当确定了 (gcd) ,考虑如何求出最小花费

    可以设计一个 dp,令 (f_{i, 0/1/2}) 为截至第 (i) 位,没有删除过区间 / 正在删除一段区间 / 已经删除了一段区间 所能得到的最小花费

    可以列出方程 (egin{cases}f_{i, 0}=f_{i-1, 0}+cost_i\f_{i, 1}=min(f_{i-1, 0}, f_{i-1, 1})+A\f_{i, 2}=min(f_{i-1, 1}, f_{i-1, 2})+cost_iend{cases})

    时间复杂度 (O(nlog n))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const int maxn = 1e6 + 10;
    ll f[3][maxn];
    int n, A, B, a[maxn];
    
    inline ll calc(int x, int P) {
      if (x % P == 0) return 0;
      if ((x + 1) % P == 0 || (x - 1) % P == 0) {
        return B;
      }
      return 1ll << 40;
    }
    
    inline ll check(int P) {
      bool flg = 1;
      f[1][0] = f[2][0] = 1ll << 40;
      for (int i = 1; i <= n; i++) {
        ll v = calc(a[i], P);
        f[0][i] = f[0][i - 1] + v;
        f[1][i] = min(f[0][i - 1], f[1][i - 1]) + A;
        f[2][i] = min(f[1][i - 1], f[2][i - 1]) + v;
        flg &= i == 1 || f[0][i - 1] > f[1][i - 1];
      }
      return min(f[0][n], min(flg ? 1ll << 60: f[1][n], f[2][n]));
    }
    
    inline ll factor(int x) {
      int tmp = sqrt(x);
      ll res = 1ll << 60;
      for (int i = 2; i <= tmp; i++) {
        if (x % i == 0) {
          res = min(res, check(i));
          while (x % i == 0) x /= i;
        }
      }
      if (x > 1) res = min(res, check(x));
      return res;
    }
    
    int main() {
      scanf("%d %d %d", &n, &A, &B);
      for (int i = 1; i <= n; i++) {
        scanf("%d", a + i);
      }
      if (n == 1) return puts("0");
      int s[7];
      s[1] = a[1];
      s[2] = a[1] - 1;
      s[3] = a[1] + 1;
      s[4] = a[n];
      s[5] = a[n] - 1;
      s[6] = a[n] + 1;
      ll ans = 1ll << 60;
      for (int i = 1; i < 7; i++) {
        ans = min(ans, factor(s[i]));
      }
      printf("%I64d", ans);
      return 0;
    }
    
  • 相关阅读:
    Leetcode:50. Pow(x, n)
    loj 2759「JOI 2014 Final」飞天鼠
    bzoj 3569 DZY Loves Chinese II
    CF407D Largest Submatrix 3
    bzoj 3837 pa2013 Filary
    bzoj 4722 由乃
    CF1105E Helping Hiasat
    loj 6043「雅礼集训 2017 Day7」蛐蛐国的修墙方案
    luogu P2605 [ZJOI2010]基站选址
    luogu P3226 [HNOI2012]集合选数
  • 原文地址:https://www.cnblogs.com/Juanzhang/p/11001692.html
Copyright © 2020-2023  润新知