• 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] e 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;
    }
    
  • 相关阅读:
    Mybatis逆向工程构建项目实例.
    JVM调优总结 -Xms -Xmx -Xmn -Xss
    mvn test 执行testng测试用例
    jmeter 发送http请求,并把获取到的请求的订单信息保存到文件中
    jenkins job构建后汇总结果到同一个文本文档中去
    shell 批量查看job 配置
    jenkins 发送邮件模板
    jenkins 发送邮件失败
    maven 私服中央库使用阿里云库
    jenkins 下载插件失败处理办法
  • 原文地址:https://www.cnblogs.com/quanjun/p/12208914.html
Copyright © 2020-2023  润新知