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);
}
}
}
浙公网安备 33010602011771号