2.16

2.16

[P1070 NOIP 2009 普及组] 道路游戏 - 洛谷 (luogu.com.cn)

  • \(dp[i]\)表示前i个时间,所最多收集的金币
  • 如果是\(O(n^3)\)的做法的话,我们只需要枚举起点,步数,时间就行了
  • 但是可能是数据弱的问题,本题这样做就ac了,标答应该用优先队列维护为\(O(n^2{logn})\)
import java.io.*;
import java.util.*;
import java.util.zip.ZipEntry;

public class Main implements Runnable {

    static StreamTokenizer cin = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static PrintWriter cout = new PrintWriter(new OutputStreamWriter(System.out));
    static int n, m, p;
    static final int N = (int) (1e3 + 10);
    static int[][] money = new int[N][N];
    static int[] costs = new int[N];
    static int[] dp = new int[N];

    public static void main(String[] args) {
        new Thread(null, new Main(), "", 1 << 29).start();
    }

    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int) cin.nval;

    }

    @Override
    public void run() {
        try {
            n = nextInt();m = nextInt();p = nextInt();
            for (int i = 1; i <= n; i++) {
                for (int j = 1; j <= m; j++) {
                    money[i][j] = nextInt();// 路i在j秒时的金币
                }
            }

            for (int i = 1; i <= n; i++) {
                costs[i] = nextInt();
                costs[i + n] = costs[i];
            }

            Arrays.fill(dp, -0x3f3f3f3f);
            dp[0] = 0;
            for (int t = 1; t <= m; t++) {
                for (int start = 1; start <= n; start++) {
                    int ans = dp[t - 1] - costs[start];
                    for (int cnt = 0; cnt < p && cnt + t <= m; cnt++) {
                        int now = (start + cnt) > n ? (start + cnt) % n : start + cnt;
                        ans = ans + money[now][t + cnt];
                        dp[t + cnt] = Math.max(dp[t + cnt], ans);
                    }
                }
            }

            cout.println(dp[m]);
            cout.flush();

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}

[P4342 IOI 1998] Polygon - 洛谷 (luogu.com.cn)

  • 环形区间,写了一个区间dp,但是wa得了80分
  • 需要讨论,因为结点为负数而且存在乘号
  • 负数*负数得正数
  • 需要讨论,详细看这篇

[题解 P4342 【IOI1998]Polygon】 - 洛谷专栏 (luogu.com.cn)

import java.io.*;
import java.util.*;
import java.util.zip.ZipEntry;

public class Main implements Runnable {

//    static StreamTokenizer cin = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static Scanner scanner = new Scanner(System.in);
    static PrintWriter cout = new PrintWriter(new OutputStreamWriter(System.out));
    static int n;
    static final int N = 55;
    static node[] nodes = new node[N * 2];
    static int[][] dp = new int[N * 2][N * 2];
    static int[][] g = new int[N * 2][N * 2];

    public static void main(String[] args) {
        new Thread(null, new Main(), "", 1 << 29).start();
    }

    public static int nextInt() throws IOException {
//        cin.nextToken();
//        return (int) cin.nval;
        return scanner.nextInt();
    }

    public static String next() throws IOException {
        return scanner.next();
    }

    public static char nextChar() {
        return scanner.next().charAt(0);
    }

    @Override
    public void run() {
        try {
            n = nextInt();
            for (int i = 1; i <= n * 2; i++) {
                Arrays.fill(dp[i], -0x3f3f3f3f);
                Arrays.fill(g[i], 0x3f3f3f3f);
            }
            for (int i = 1; i <= n; i++) {
                nodes[i] = new node();
                char t = nextChar();int val = nextInt();
                nodes[i].val = val;
                if (t == 't') {
                    nodes[i].cnt = 1;
                } else {
                    nodes[i].cnt = 2;
                }
            }

            for (int i = 1; i <= n; i++) {
                nodes[i + n] = new node();
                nodes[i + n] = nodes[i];

                dp[i][i] = nodes[i].val;dp[i + n][i + n] = nodes[i + n].val;
                g[i][i] = nodes[i].val;g[i + n][i + n] = nodes[i + n].val;
            }

            for (int len = 2; len <= n; len++) {
                for (int left = 1; left + len - 1 <= n * 2; left++) {
                    int right = left + len - 1;
                    for (int k = left; k < right; k++) {
                        if (nodes[k + 1].cnt == 1) {
                            dp[left][right] = Math.max(dp[left][right], dp[left][k] + dp[k + 1][right]);
                            g[left][right] = Math.min(g[left][right], g[left][k] + g[k+1][right]);
                        } else {
                            dp[left][right] = Math.max(dp[left][right], Math.max(dp[left][k] * dp[k+1][right], Math.max(g[left][k] * g[k+1][right], Math.max(dp[left][k] * g[k+1][right], g[left][k] * dp[k+1][right]))));
                            g[left][right] = Math.min(g[left][right], Math.min(dp[left][k] * dp[k+1][right], Math.min(g[left][k] * g[k+1][right], Math.min(dp[left][k] * g[k+1][right], g[left][k] * dp[k+1][right]))));
                        }
                    }
                }
            }

            int ans = -0x3f3f3f3f;
            for (int i = 1; i <= n; i++) {
                ans = Math.max(ans, dp[i][i + n - 1]);
            }
            cout.println(ans);
            for (int i = 1; i <= n; i++) {
                if (ans == dp[i][i + n - 1]) {
                    cout.print(i + " ");
                }
            }
            cout.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    //-7 4 2 5 -7 4 2 5
    static class node {
        int val;
        int cnt;//1为正,2为乘
    }

}

P1220 关路灯 - 洛谷 (luogu.com.cn)

  • 设想\([left, right]\)这个区间的路灯,我们要求出这个区间的dp,我们可能由哪写转移可能。
  • 其实可以想象就两种转移方式,$[left + 1, right] -> [left, right] or [left, right - 1]->[left, right] $
  • 根据推测,我们可以知道就是老张打算关下一栈灯时一定是在区间左右两个端点之一,因为老张不可能在区间里面行走,这只会浪费时间,而使得计算值不可能为最优
  • 那么转移方式无外乎各位两种,\([left + 1, right]->[left, right]\)只可能由老张在\(left + 1, right\)两个点转移,同理另一个方式也是
  • 如此根据画图就不难得出转移方程
import java.io.*;
import java.util.*;
import java.util.zip.ZipEntry;

public class Main implements Runnable {

    static StreamTokenizer cin = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
    static PrintWriter cout = new PrintWriter(new OutputStreamWriter(System.out));
    static int n, c;
    static final int N = 55;
    static deng[] dengs = new deng[N];
    static int[][][] dp = new int[N][N][2];//0 最左端 1 最右端
    static int[] sum = new int[N];

    public static void main(String[] args) {
        new Thread(null, new Main(), "", 1 << 29).start();
    }

    public static int nextInt() throws IOException {
        cin.nextToken();
        return (int) cin.nval;
    }

    public static String next() throws IOException {
        cin.nextToken();
        return cin.sval;
    }

    @Override
    public void run() {
        try {

            n = nextInt();c = nextInt();
            for (int i = 1; i <= n; i++) {
                dengs[i] = new deng();
                int x = nextInt();int power = nextInt();
                dengs[i].num = i; dengs[i].x = x; dengs[i].power = power;
                sum[i] = sum[i - 1] + dengs[i].power;
            }

            for(int i = 1; i <= n; i++) {
                for (int j = 1; j <= n; j++) {
                    Arrays.fill(dp[i][j], 0x3f3f3f3f);
                }
            }

            dp[c][c][0] = 0;
            dp[c][c][1] = 0;

            for (int len = 2; len <= n; len++) {
                for (int left = 1; left + len - 1 <= n; left++) {
                    int right = left + len - 1;
                    //迭代right点
                    dp[left][right][1] = Math.min(dp[left][right - 1][0] + (dengs[right].x - dengs[left].x) * (sum[n] - sum[right - 1] + sum[left - 1]),
                                        dp[left][right - 1][1] + (dengs[right].x - dengs[right - 1].x) * (sum[n] - sum[right - 1] + sum[left - 1]));
                    dp[left][right][0] = Math.min(dp[left + 1][right][0] + (dengs[left + 1].x - dengs[left].x) * (sum[n] - sum[right] + sum[left]),
                                        dp[left + 1][right][1] + (dengs[right].x - dengs[left].x) * (sum[n] - sum[right] + sum[left]));
                }
            }

            int ans = Math.min(dp[1][n][0], dp[1][n][1]);
            cout.println(ans);
            cout.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    static class deng{
        int num;
        int x;
        int power;
    }
}
posted @ 2025-02-16 16:14  Mikkeykarl  阅读(8)  评论(0)    收藏  举报