# C

# 题目大意

给你 nn 个数 a1,...,ana_1, ..., a_n,找到满足 ji=ai+aj(i<j)j-i = a_i + a_j~(i < j)(i,j)(i,j) 的个数

# 数据范围

  • 1n2×1051 \le n \le 2 \times 10^5

# 题解

变换原式为 ai+i=jaja_i+i = j - a_j,维护一个 map<int, int> 记录已经有的 ai+ia_i + i,对于每次新的 jj,累加即可

C++
1
2
3
4
5
6
7
void solve () {
cin >> n, a = vector<int>(n + 1);
int res = 0;
for (int i = 1; i <= n; i++)
cin >> a[i], res += ii[i - a[i]], ii[a[i] + i]++;
cout << res << '\n';
}

# D

# 题目大意

你将收到 nn 份礼物,你有一个情绪值 valval,非负整数。每收到一份礼物,你的情绪值会发生变化,每份礼物有价值 PP、情绪上升度 AA、情绪下降度 BB

  • 当前礼物的 PvalP \ge val 时,val+=Aval += A
  • 当前礼物的 P<valP < val 时,val=max(0,valB)val = max(0, val - B)

现在有 QQ 个询问,在第 ii 个询问中,给定一个非负整数 XX,请问若最初 val=xval = x,收到所有礼物之后,valval 是多少

# 数据范围

  • 1n1041 \le n \le 10^4
  • 1Ai,Bi,Pi5001 \le A_i, B_i, P_i \le 500
  • 1Q5×1051 \le Q \le 5 \times 10^5
  • 0X1090 \le X \le 10^9

# 题解

这是一道 DPDP 题,本题重要的是要发现 1Ai,Bi,Pi5001 \le A_i,B_i,P_i \le 500 这个关键条件

  • 如果一开始的情绪值很大,那么就会一直减
  • 否则则会在 1000\le 1000 的范围变化,为什么?
    • 如果 val>500val > 500,那么一定会减少
    • 如果 val500val \le 500,那么就算会增加,也不会超过 10001000

我们不妨对 10001000 以内的情况去做 DPDP

  • 状态变量dpi,jdp_{i,j} 代表从第 ii 件礼物开始,开始收礼物的 valvaljj,的最终的心情
  • 转移方程
    • 如果 j>Pij > P_i,代表下一步心情得减,dp_{i,j}=dp_
    • 如果 jPij \le P_i,代表下一步心情得加,dp_{i,j}=dp_
  • 倒着 DPDP

然后通过前缀和维护一个 bbprepre 数组,用二分去找,我初步给出的 valval 从那个下标开始,会进入 10001000 以内,然后直接用 DPDP 的值

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void solve () {
cin >> n;
p = vector<int>(n + 10), a = vector<int>(n + 10), b = vector<int>(n + 10), pre = vector<int>(n + 1);
dp = vector<vector<int>>(n + 10, vector<int>(1010));

for (int i = 1; i <= n; i++)
cin >> p[i] >> a[i] >> b[i];

for (int j = 0; j <= 1000; j++)
dp[n + 1][j] = j;

for (int i = n; i >= 1; i--)
for (int j = 0; j <= 1000; j++)
dp[i][j] = dp[i + 1][(j > p[i] ? max((int)0, j - b[i]) : j + a[i])];

for (int i = 1; i <= n; i++)
pre[i] = pre[i - 1] + b[i];

cin >> q;
while (q--) {
cin >> x;
if (x - 1000 > pre[n])
cout << x - pre[n] << '\n';
else if (x <= 1000)
cout << dp[1][x] << '\n';
else {
int idx = lower_bound(pre.begin() + 1, pre.begin() + n + 1, x - 1000) - pre.begin();
cout << dp[idx + 1][x - pre[idx]] << '\n';
}
}
}

更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

duoxichangan 微信支付

微信支付

duoxichangan 支付宝

支付宝