2.6

2.6

P1725 琪露诺 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

  • 首先我们先简化一下本题,如果我们假设有一个数为\(x\),我们每次从某一个地点到另一个地点需要加上\(x\),那么可以得到线性模板dp,也就是\(dp[j + x] = max(dp[j]) + 1\), 注意这里有两个注意的点:
  • 1 \(dp[i]\)定义为到达点i时,得到的最大冰冻指数
  • 2 不可以把转移方程理解为\(dp[j + x] = max(dp[j] + 1)\),这样的话我们并不是求得的上一步最佳,而是假设移动到此点的最佳。
  • ok, 但是题目有一个区间,即我们要求得\(dp[i] = max(dp[i - r], dp[i - r + 1].... dp[i - l])\),注意就是我们从i到达下一个点\(i -> [i + l, i + r]\),等价于从j(上一个点)到i,即j的区间\(j -> [i - r, i - l]\),那么有一个想法脱口而出,就是我们用i枚举\([L, N]\),然后用j枚举\(max(dp[i - r], dp[i - r + 1].... dp[i - l])\),值得注意的是\(i在[0, L)\)时,是不可以走到的,那么我们就把dp数组设置为极小,就ok了,不然WA substack2.1两个点
  • 但是还不够的是,上述方法复杂度为\(O(N^2)\),so考虑优化
  • 很明显,优化查找最大值就ok了,这里选用优先队列,甚至还用java复习了一下底层源码真是xs).....
  • ok,那么思路上基本没问题了,复杂度达到\(O(NlogN)\),本题ac
import java.io.*;
import java.util.*;

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, L, R;
    static final int INT = (int) (2e5 + 10);
    static int[] A = new int[INT];
    static int[] dp = new int[INT];
    static boolean[] str = new boolean[INT];
    static long ans = -0x3f3f3f3f;
    static Queue<mokuai>queue = new PriorityQueue<>(new Comparator<mokuai>() {
        @Override
        public int compare(mokuai o1, mokuai o2) {
            return o2.val - o1.val;
        }
    });

    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(); L=nextInt(); R=nextInt();
            for (int i = 0; i <= N; i++) {
                A[i]=nextInt();
                //dp[i] = A[i];
            }
            Arrays.fill(dp, -0x3f3f3f3f);


            dp[0] = 0;
            for(int i = L; i <= N; i++) {
                queue.add(new mokuai(i - L, dp[i - L]));
                if (queue.size() > R - L + 1) {
                    queue.remove(new mokuai(i - R - 1, dp[i - R - 1]));
                }
                mokuai top = queue.peek();
                dp[i] = top.val + A[i];

                if (i + R > N) {
                    ans = Math.max(ans, dp[i]);
                }
            }

            cout.println(ans);
            cout.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    static class mokuai{
        int suoyin;
        int val;

        public mokuai(int suoyin, int val) {
            this.suoyin = suoyin;
            this.val = val;
        }

        @Override
        public boolean equals(Object o) {
            if (o == null || getClass() != o.getClass()) return false;
            mokuai mokuai = (mokuai) o;
            return suoyin == mokuai.suoyin && val == mokuai.val;
        }

        @Override
        public int hashCode() {
            return Objects.hash(suoyin, val);
        }
    }
}

P4933 大师 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

  • 本题难在不知道怎么去设置dp转移数组
  • 看题解后设置为\(dp[i][j]\),以数字i结束,j为公差的等差数列个数,转移方程即为\(dp[i][k] += dp[j][k] + 1\),以 i 结尾且上一个数是 j的公差为k的等差数列数量是以j结尾公差为k的等差数列数加一
  • 注意2个点
  • 1 ans的求解问题,在\(dp[i][0]\)时要加1,记录只有一个塔的时候的情况
  • 2 公差可能为负,所以P = 20000(因为最高为20000,最矮为0)
  • 最后只要统计,在公差为k时,各个数为结尾的总和即可
  • 当时还纠结了一个问题,同一个等差数列,但是结尾数不同,统计两次,不会重复吗?笔者演算了一下,是不会的,假设有一等差为2的等差数列\(2, 4, 6, 8\)\(dp[8][2] = 3\), 我们统计时是要加3的,如果我们加一个数字10,变为\(2,4,6,8,10\),那么统计\(dp[10][2]\),为4,发现我们统计的数列都是不一样的,\((10,8),(10,8,6),(10,8,6,4),(10,8,6,4,2)\),所以这么统计是没有问题的。
  • 这也回答了为什么不加\(ans += dp[i][h[i] - h[j] + p] + 1\)而是加\(ans += dp[j][h[i] - h[j] + p] + 1;\)
import java.io.*;
import java.util.*;

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;
    static final int N = (int) (1e3 + 10);
    static final int M = (int) (4e4 + 10);
    static final int mod = 998244353;
    static int[] h = new int[N];
    static int[][] dp = new int[N][M];

    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();
            for (int i = 1; i <= n; i++) {
                h[i] = nextInt();
            }
            int ans = 0;
            int p = 20000;
            for (int i = 1; i <= n; i++) {
                //ans++;
                for (int j = i - 1; j > 0; j--) {
                    dp[i][h[i] - h[j] + p] += dp[j][h[i] - h[j] + p] + 1;
                    dp[i][h[i] - h[j] + p] %= mod;
                    //ans += dp[j][h[i] - h[j] + p] + 1;
                    //ans %= mod;
                }
            }

            for (int i = 1; i <= n; i++) {
                ans++;
                for(int j = 1; j < M; j++) {
                    ans += dp[i][j];
                    ans %= mod;
                }
            }
            cout.println(ans);
            cout.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


}
posted @ 2025-02-06 19:48  Mikkeykarl  阅读(17)  评论(0)    收藏  举报