CF892C Pride 题解 区间DP

题目链接:http://codeforces.com/contest/892/problem/C
CF原版题解题解链接:http://codeforces.com/blog/entry/55841

题目描述(人名略有改变)

灵灵和聪聪在玩一个叫做“相约九八”的游戏。
一开始给他们一个数组 \(a_1,a_2, \cdots ,a_n\)
然后每次操作他们可以选择数组中相邻的两个数,
我们假设这两个数的数值分别为 \(x\)\(y\)
我们可以求出他们的最大公约数 \(gcd(x,y)\) ,然后将其中一个数的数值变为 \(gcd(x,y)\)
请你帮他们计算一下,他们最少需要几步能够将数组中的所有元素都变为 \(1\)

输入格式

输入的第一行包含一个整数 \(n\)\(1 \le n \le 2000\) )——表示数组中元素的个数。
输入的第二行包含 \(n\) 个整数:\(a_1,a_2, \cdots ,a_n\)\(1 \le ai \le 10^9\) ),用于表示数组中的每个元素。

输出格式

如果没有办法将数组中的所有元素都变成 \(1\) ,则输出 \(-1\) ;否则输出将数组中的所有元素都变为 \(1\) 的最少步数。

样例输入1

5
2 2 3 4 6

样例输出1

5

样例输入2

4
2 4 6 8

样例输出2

-1

样例输出3

3
2 6 9

样例输出3

4

【样例解释】
对于样例1,我们可以使用如下 \(5\) 步将数组中的所有元素都转换成 \(1\)

  • \([2, 2, 3, 4, 6]\)
  • \([2, 1, 3, 4, 6]\)
  • \([2, 1, 3, 1, 6]\)
  • \([2, 1, 1, 1, 6]\)
  • \([1, 1, 1, 1, 6]\)
  • \([1, 1, 1, 1, 1]\)

题目分析

本题设计内容:区间DP。
我们设 \(cnt1\)\(a\) 中元素 \(1\) 的个数。
如果 \(0 < cnt1\) ,那么答案就是 \(n - cnt1\)
否则我们需要找到数组 \(a\)\(gcd\) (这里 \(gcd\) 表示最大公约数)等于 \(1\) 的最短的连续子串。
我们定义数组中从坐标 \(L\) 开始到坐标 \(R\) 结束的这段区间内的所有元素的 \(gcd\)\(dp[L][R]\)
可以得到状态转移方程为

  • \(dp[i][i] = a[i]\)
  • \(dp[i][j] = gcd(dp[i][j-1], a[j])\)

如果 \(dp[1][n] \ne 1\) ,则直接输出 \(-1\)
否则,我们假设通过 \(dp\) 数组求得了最短的长度 \(mlen\) (表示最少有 \(mlen\) 个相邻元素它们的 \(gcd\) 等于 \(1\) ),
那么答案就是 \(mlen-1 + n-1\)
实现代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2020;
 
int n, a[maxn], dp[maxn][maxn], cnt1;
 
int get_min_len() {
    for (int i = 0; i < n; i ++) dp[i][i] = a[i];
    for (int l = 1; l <= n; l ++) {
        for (int i = 0; i+l-1 < n; i ++) {
            int j = i + l - 1;
            dp[i][j] = __gcd(dp[i][j-1], a[j]);
            if (dp[i][j] == 1) return l;
        }
    }
    return -1;
}
 
int main() {
    cin >> n;
    for (int i = 0; i < n; i ++) {
        cin >> a[i];
        if (a[i] == 1) cnt1 ++;
    }
    if (cnt1 > 0) {
        cout << n - cnt1 << endl;
        return 0;
    }
    int mlen = get_min_len();
    if (mlen == -1) {
        cout << -1 << endl;
    } else {
        cout << mlen-1 + n-1 << endl;
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/quanjun/p/12208914.html