zoukankan      html  css  js  c++  java
  • [动态规划] Codeforces 1497E2 Square-free division (hard version)

    题目大意

    给定由 (n(1leq nleq 2cdot 10^5)) 个正整数组成的数列({a_n}),你需要把这个数列分成若干个连续段,使得每个连续段内任意两个不同位置上数字的乘积不为完全平方数。初始时你可以把不多于 (k (0leq kleq 20)) 个位置上的数修改成任意正整数。请最小化分出的连续段的数目。

    题解

    容易发现,若两个数的乘积为完全平方数,则两个数分别除尽各自的平方因子后相同。所以我们可以先除尽数列中每个数的平方因子,问题就转化为要使得每个连续段中的数是互不相同的。

    (l[i][x]) 表示以第 (i) 个位置结尾的连续段,之前修改不超过 (x) 个位置,该段所能延伸到的最远的左端点的位置。

    可以发现,若我们固定住 (x),不断递增 (i)(l[i][x]) 是单调右移的,我们可以维护一个单调右移的指针,并且开一个桶记录该指针到 (i) 之间每个数出现的次数,若当前存在两个数出现了两次及以上,就要右移指针,直到每个数在该段内只出现一次。于是我们可以以 (O(nk)) 的时间复杂度求得所有 (l[i][x])

    (dp[i][j]) 表示前 (i) 个位置中修改了不超过 (j) 个位置,所划分出的最少的连续段数。

    那么有 (dp[i][j]=min(dp[i][j],dp[l[i][x]-1][j-x]+1))

    时间复杂度 (O(nk^2))

    ps: "维护每个位置最远能延伸到的地方"这种思想挺重要的,被这坑了很多次了。

    Code

    #include <bits/stdc++.h>
    using namespace std;
     
    #define RG register int
    #define LL long long
     
    template<typename elemType>
    inline void Read(elemType& T) {
        elemType X = 0, w = 0; char ch = 0;
        while (!isdigit(ch)) { w |= ch == '-';ch = getchar(); }
        while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
        T = (w ? -X : X);
    }
     
    int dp[200001][21], l[200001][21], a[200001], b[10000010];
    int cnt[10000010];
    int T, N, K;
     
    int div(int x) {
        int res = 1;
        for (LL i = 2; i * i <= x; ++i) {
            int cnt = 0;
            while (x % i == 0) { x /= i; ++cnt; }
            if (cnt & 1) res *= i;
        }
        if (x != 1) res *= x;
        return res;
    }
     
    void Solve() {
        for (int k = 0;k <= K;++k) {
            int num = 0, p = 1;
            for (int i = 1;i <= N;++i) {
                ++cnt[a[i]];
                if (cnt[a[i]] > 1) ++num;
                while (num > k) {
                    if (cnt[a[p]] > 1) --num;
                    --cnt[a[p]];++p;
                }
                l[i][k] = p;
            }
            while (p <= N) { cnt[a[p]] = 0; ++p; }
        }
        for (int i = 1;i <= N;++i)
            for (int k = 0;k <= K;++k)
                for (int x = 0;x <= k;++x)
                    dp[i][k] = min(dp[i][k], dp[l[i][x] - 1][k - x] + 1);
        int ans = 1 << 30;
        for (int k = 0;k <= K;++k)
            ans = min(ans, dp[N][k]);
        printf("%d
    ", ans);
    }
     
    int main() {
        Read(T);
        while (T--) {
            Read(N);Read(K);
            for (int i = 1;i <= N;++i) {
                Read(a[i]);
                if (!b[a[i]]) b[a[i]] = div(a[i]);
                a[i] = b[a[i]];
                for (int j = 0;j <= K;++j)
                    dp[i][j] = l[i][j] = 0x3f3f3f3f;
            }
            Solve();
        }
        return 0;
    }
    
  • 相关阅读:
    Android 解决小米手机Android Studio安装app 报错的问题It is possible that this issue is resolved by uninstalling an existi
    Android Unresolved Dependencies
    Android studio 自定义打包apk名
    Android Fragment与Activity交互的几种方式
    魅族和三星Galaxy 5.0webView 问题Android Crash Report
    Android几种常见的多渠道(批量)打包方式介绍
    Android批量打包 如何一秒内打完几百个apk渠道包
    上周热点回顾(9.30-10.6)团队
    上周热点回顾(9.23-9.29)团队
    上周热点回顾(9.16-9.22)团队
  • 原文地址:https://www.cnblogs.com/AEMShana/p/14582191.html
Copyright © 2011-2022 走看看