Luo Gu solution to a problem P2072 [religion]

I see the solution to a problem big brother, why the first \ (1 \) sub-tasks with \ (DP \) count it? You can use greedy ah. . .

Closer to home.

For the first sub-task, direct greedy, how many can take much to take, and then take after take full cleared.

For the second sub-task, considering \ (DP \) .

Set \ (f_i \) before the representation \ (i \) a minimum value of a risk of believers, there are:

\(f_i=\min\{f_j+danger_{i,j}\}\) \((danger_{i,j}<=k)\)

Wherein \ (danger_ {i, j} \) represents \ (i, j \) dangerous values between.

The question is: \ (danger_ {i, J} \) how find it?

\ (1 \) violence to solve the equation when running.

Time complexity: \ (O (n-^. 3) \) , obviously \ (T \) .

\ (2 \) pretreatment.

Order \ (CNT \) as a counter, when the discovery of new religious \ (CNT ++ \) , and mark this religion, and each section corresponding to \ (danger_ {i, j} \) is the \ (CNT \)

Time complexity: \ (O (^ n-2) \) , it can be over.

As for the border, apparently \ (f_0 = 0, f_1 = 1 \)

The goal is naturally \ (f_n \)

\ (The AC \) \ (Code \) (code \ (sum_ {i, j} \) is the \ (danger_ {I, J} \) )

#include <iostream>
#include <cstring>
using namespace std;

int n, m, k, a[10010], cnt, ans, sum[1010][1010], f[1010];
bool vis[10010];

int main() {
    cin >> n >> m >> k;
    for (int i=1; i<=n; i++) 
        cin >> a[i];
    for (int i=1; i<=n; i++) {
        cnt = 0;
        memset(vis, false, sizeof(vis));// 一定要清空!
        for (int j=i; j<=n; j++) {
            if (!vis[a[j]]) {
                vis[a[j]] = true;
                cnt++;
            }
            sum[i][j] = cnt;
        }
    }
    cnt = 0;
    memset(vis, false, sizeof(vis));//注意,出来时也要清空!我被坑了好长时间TAT
    for (int i=1; i<=n; i++) {
        if (!vis[a[i]]) {
            vis[a[i]] = true;
            cnt++;
        }
        if (cnt > k) {
            ans++;
            cnt = 1;
            memset(vis, false, sizeof(vis));//记得清空!
            vis[a[i]] = true;
        }
        if (i == n)
            ans++;
    }
    cout << ans << endl;
    f[0] = 0;
    f[1] = 1;//初始化莫忘掉
    for (int i=2; i<=n; i++) {
        f[i] = 1e9;//因为取最小值,所以初值要赋大
        for (int j=1; j<=i; j++) 
            if (sum[j][i] <= k) //而且危险值不能超过k
                f[i] = min(f[i], f[j-1]+sum[j][i]);
    }
    cout << f[n] << endl;
    return 0; //完结撒花!
}

Guess you like

Origin www.cnblogs.com/zyh-cr7/p/12237196.html