2022杭电多校(三)

文章目录

  • 2022杭电多校(三)
    • 一、比赛小结
    • 二、题目分析及解法(基础题)
      • 1001、Equipment Upgrade
      • 1002、Boss Rush
      • 1003、Cyber Language
      • 1008、Laser Alarm
      • 1009、Package Delivery
      • 1011、Taxi
      • 1012、Two Permutations
    • 二、题目分析及解法(进阶题)
      • 1004、Divide the Sweets
      • 1005、Spanning Tree Game
      • 1006、Dusk Moon
      • 1007、Shallow Moon
      • 1010、Range Reachability Query

一、比赛小结

比赛链接:Problems (hdu.edu.cn)

二、题目分析及解法(基础题)

1001、Equipment Upgrade

题目链接:Problem - 7162 (hdu.edu.cn)

题意:

一共有 n n n 级,在第 i i i 级时,升级到 i + 1 i+1 i+1 级的概率为 p i p_i pi​ ,且要被花费 c i c_i ci​ 元,并且还有 ( 1 − p i ) ω j ∑ k = 1 i ω k \displaystyle (1-p_i)\frac{\omega_j}{\sum_{k=1}^i\omega_k} (1−pi​)∑k=1i​ωk​ωj​​ 的概率降到第 i − j i-j i−j 级,求从 0 0 0 级升到 n n n 级的期望花费。

题解:

我们先来推下式子:

E n = 0 E_n=0 En​=0

E i = c i + p i ⋅ E i + 1 + 1 − p i ∑ j = 1 i ω j ⋅ ( ∑ j = 1 i ω j ⋅ E i − j ) \displaystyle E_i=c_i+p_i \cdot E_{i+1}+\frac{1-p_i}{\sum_{j=1}^i\omega_j}\cdot (\sum_{j=1}^i\omega_j\cdot E_{i-j}) Ei​=ci​+pi​⋅Ei+1​+∑j=1i​ωj​1−pi​​⋅(j=1∑i​ωj​⋅Ei−j​)

E i + 1 = E i − c i − 1 − p i ∑ j = 1 i ω j ⋅ ( ∑ j = 1 i ω j ⋅ E i − j ) p i \displaystyle E_{i+1}=\frac{E_i-c_i-\frac{1-p_i}{\sum_{j=1}^i\omega_j}\cdot (\sum_{j=1}^i{\omega_j\cdot E_{i-j}})}{p_i} Ei+1​=pi​Ei​−ci​−∑j=1i​ωj​1−pi​​⋅(∑j=1i​ωj​⋅Ei−j​)​

然后设 E i = a i ⋅ E 0 + b i E_i=a_i\cdot E_0+b_i Ei​=ai​⋅E0​+bi​ ,则有:

a 0 = 1 , b 0 = 0 a_0=1, \ b_0=0 a0​=1, b0​=0

a i + 1 = a i − 1 − p i ∑ j = 1 i ω j ⋅ ( ∑ j = 1 i ω j ⋅ a i − j ) p i \displaystyle a_{i+1}=\frac{a_i-\frac{1-p_i}{\sum_{j=1}^i\omega_j}\cdot (\sum_{j=1}^i\omega_j \cdot a_{i-j})}{p_i} ai+1​=pi​ai​−∑j=1i​ωj​1−pi​​⋅(∑j=1i​ωj​⋅ai−j​)​

b i + 1 = b i − c i − 1 − p i ∑ j = 1 i ω j ⋅ ( ∑ j = 1 i ω j ⋅ b i − j ) p i \displaystyle b_{i+1}=\frac{b_i-c_i-\frac{1-p_i}{\sum_{j=1}^i\omega_j}\cdot (\sum_{j=1}^i\omega_j\cdot b_{i-j})}{p_i} bi+1​=pi​bi​−ci​−∑j=1i​ωj​1−pi​​⋅(∑j=1i​ωj​⋅bi−j​)​

这个递推有卷积的形式,因此可以用 分治+NTT 来做,分治NTT已经变成常识了(悲

代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;
namespace poly {typedef long long ll;
const int mod = 998244353;
const int maxn = 1e6 + 10;
ll invi[maxn];
// 记得先init()!!!!!!!!!
void init() {invi[1] = 1;for (int i = 2; i < maxn; i++) {invi[i] = (mod - mod / i) * invi[mod % i] % mod;}
}
// 快速幂
ll quickpow(ll x, ll y) {ll ans = 1;while (y) {if (y & 1) ans = ans * x % mod;y >>= 1;x = x * x % mod;}return ans;
}
// 二次剩余
ll modsqrt(ll x) {if (mod == 2) return x % mod;if (quickpow(x, mod - 1 >> 1) != 1) return -1;ll ans = 0;if (mod % 4 == 3)ans = quickpow(x, mod + 1 >> 2);else {ll b;for (b = rand() % mod; quickpow(b, mod - 1 >> 1) == 1; b = rand() % mod);ll i = mod - 1 >> 1, k = 0;do {i >>= 1;k >>= 1;if ((quickpow(x, i) * quickpow(b, k) + 1) % mod == 0) k += (mod - 1 >> 1);} while (i % 2 == 0);ans = quickpow(x, i + 1 >> 1) * quickpow(b, k >> 1) % mod;}if (ans * 2 > mod) ans = mod - ans;return ans;
}
// 蝴蝶变换
void change(ll* a, int len) {static int rev[maxn];rev[0] = 0;for (int i = 0; i < len; i++) {rev[i] = (rev[i >> 1] >> 1);if (i & 1) rev[i] |= len >> 1;}for (int i = 0; i < len; i++)if (i < rev[i]) swap(a[i], a[rev[i]]);
}
// flag=1 -> NTT , flag=-1 -> INTT , O(nlogn)
void NTT(ll* a, int len, int flag) {change(a, len);for (int h = 2; h <= len; h <<= 1) {ll uni = quickpow(3, (mod - 1) / h);  // 3 为 mod = 998244353 的原根if (flag == -1) uni = quickpow(uni, mod - 2);for (int i = 0; i < len; i += h) {ll w = 1;for (int j = i; j < i + h / 2; j++) {ll u = a[j] % mod;ll v = w * a[j + h / 2] % mod;a[j] = (u + v) % mod;a[j + h / 2] = (u - v + mod) % mod;w = w * uni % mod;}}}if (flag == -1) {ll inv = quickpow(len, mod - 2);for (int i = 0; i < len; i++) a[i] = a[i] * inv % mod;}
}
// 多项式乘法,n m 分别为 a b 最高次数
void polymul(ll* a, ll* b, ll* ans, int n, int m) {static ll tpa[maxn], tpb[maxn];memcpy(tpa, a, sizeof(ll) * (n + 1));memcpy(tpb, b, sizeof(ll) * (m + 1));int len = 1;for (; len < n + 1; len <<= 1)  // n + m + 1 !!! 本题特殊;memset(tpa + n + 1, 0, sizeof(ll) * (len - n));memset(tpb + m + 1, 0, sizeof(ll) * (len - m));NTT(tpa, len, 1);NTT(tpb, len, 1);for (int i = 0; i <= len; i++) ans[i] = tpa[i] * tpb[i] % mod;NTT(ans, len, -1);
}// // 多项式求逆,ans为最终答案数组, O(nlogn)
// void polyinv(ll* a, ll* ans, int len) {//   static ll tp[maxn];
//   memset(tp, 0, sizeof(ll) * (len << 1));
//   memset(ans, 0, sizeof(ll) * (len << 1));
//   ans[0] = quickpow(a[0], mod - 2);
//   for (int h = 2; h <= len; h <<= 1) {//     memcpy(tp, a, sizeof(ll) * h);
//     NTT(tp, h << 1, 1);
//     NTT(ans, h << 1, 1);
//     for (int i = 0; i < (h << 1); i++)
//       ans[i] = ans[i] * ((2 + mod - tp[i] * ans[i] % mod) % mod) % mod;
//     NTT(ans, h << 1, -1);
//     memset(ans + h, 0, sizeof(ll) * h);
//   }
// }
// // 多项式除法,a / b = ans1, a % b = ans2
// void polydiv(ll* a, ll* b, ll* ans1, ll* ans2, int n, int m) {//   static ll tp0[maxn];
//   int len = 1;
//   for (; len < n - m + 1; len <<= 1)
//     ;
//   memset(tp0, 0, sizeof(ll) * len);
//   for (int i = 0; i <= n; i++) ans1[n - i] = a[i];
//   for (int i = 0; i <= m; i++) ans2[m - i] = b[i];
//   for (int i = n - m + 1; i <= m; i++) ans2[i] = 0;
//   polyinv(ans2, tp0, len);
//   polymul(ans1, tp0, tp0, n, n - m);
//   for (int i = 0; i <= n - m; i++) ans1[i] = tp0[n - m - i];
//   polymul(b, ans1, ans2, m, n - m);
//   for (int i = 0; i < m; i++) ans2[i] = (a[i] - ans2[i] + mod) % mod;
// }
// // 多项式求导
// void qiudao(ll* a, ll* ans, int len) {//   for (int i = 1; i < len; i++) ans[i - 1] = a[i] * i % mod;
//   ans[len - 1] = 0;
// }
// // 多项式积分
// void jifen(ll* a, ll* ans, int len) {//   for (int i = len - 1; i; i--) ans[i] = a[i - 1] * invi[i] % mod;
//   ans[0] = 0;  // 积分常数C
// }
// // 多项式ln,a[0]!=0,O(nlogn)
// void polyln(ll* a, ll* ans, int len) {//   static ll tp1[maxn];
//   qiudao(a, tp1, len);
//   memset(tp1 + len, 0, sizeof(ll) * len);
//   polyinv(a, ans, len);
//   NTT(ans, len << 1, 1);
//   NTT(tp1, len << 1, 1);
//   for (int i = 0; i < (len << 1); i++) tp1[i] = tp1[i] * ans[i] % mod;
//   NTT(tp1, len << 1, -1);
//   jifen(tp1, ans, len);
// }
// // 多项式exp,a[0]==0,O(nlogn)
// void polyexp(ll* a, ll* ans, int len) {//   static ll tp2[maxn];
//   memset(tp2, 0, sizeof(ll) * (len << 1));
//   memset(ans, 0, sizeof(ll) * (len << 1));
//   ans[0] = 1;
//   for (int h = 2; h <= len; h <<= 1) {//     polyln(ans, tp2, h);
//     tp2[0] = ((a[0] + 1) % mod - tp2[0] + mod) % mod;
//     for (int i = 1; i < h; i++) tp2[i] = (a[i] - tp2[i] + mod) % mod;
//     memset(tp2 + h, 0, sizeof(ll) * h);
//     NTT(ans, h << 1, 1);
//     NTT(tp2, h << 1, 1);
//     for (int i = 0; i < (h << 1); i++) ans[i] = ans[i] * tp2[i] % mod;
//     NTT(ans, h << 1, -1);
//     memset(ans + h, 0, sizeof(ll) * h);
//   }
// }
// // 多项式开根,O(nlogn)
// void polysqrt(ll* a, ll* ans, int len) {//   static ll tp3[maxn], tp4[maxn];
//   memset(tp3, 0, sizeof(ll) * (len << 1));
//   memset(tp4, 0, sizeof(ll) * (len << 1));
//   memset(ans, 0, sizeof(ll) * (len << 1));
//   ans[0] = modsqrt(a[0]);  // 二次剩余
//   ll inv2 = quickpow(2, mod - 2);
//   for (int h = 2; h <= len; h <<= 1) {//     polyinv(ans, tp3, h);
//     memcpy(tp4, a, sizeof(ll) * h);
//     NTT(tp3, h << 1, 1);
//     NTT(tp4, h << 1, 1);
//     NTT(ans, h << 1, 1);
//     for (int j = 0; j < (h << 1); j++)
//       ans[j] =
//           (ans[j] * ans[j] % mod + tp4[j]) % mod * inv2 % mod * tp3[j] % mod;
//     NTT(ans, h << 1, -1);
//     memset(ans + h, 0, sizeof(ll) * h);
//   }
// }}  // namespace poly
typedef long long ll;
const int maxn = 1e6 + 10;
const int mod = 998244353;int n;
int c[maxn], w[maxn];
int p[maxn], pre[maxn], invp[maxn];
int ea[maxn], eb[maxn];
int fa[maxn], fb[maxn];
int ta[maxn], tb[maxn], tw[maxn];void solve(int l, int r) {if (l == r) {if (l) {ea[l + 1] = ((ea[l] - (1ll - p[l]) * fa[l] % mod * pre[l]) % mod + mod) *invp[l] % mod;eb[l + 1] =((eb[l] - c[l] - (1ll - p[l]) * fb[l] % mod * pre[l]) % mod + mod) *invp[l] % mod;}return;}int mid = (l + r) >> 1;solve(l, mid);// !!!importantfor (int i = 0; i < maxn && i <= 2 * (r - l); i++) ta[i] = tb[i] = tw[i] = 0;for (int i = l; i <= mid; i++) ta[i - l] = ea[i], tb[i - l] = eb[i];for (int i = 1; i <= r - l; i++) tw[i] = w[i];poly::polymul(ta, tw, ta, r - l, r - l);poly::polymul(tb, tw, tb, r - l, r - l);for (int i = mid + 1; i <= r; i++) {fa[i] = (fa[i] + ta[i - l]) % mod;fb[i] = (fb[i] + tb[i - l]) % mod;}solve(mid + 1, r);
}signed main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);poly::init();int _;cin >> _;while (_--) {cin >> n;for (int i = 0; i < n; i++) {int x;cin >> x >> c[i];p[i] = x * poly::invi[100] % mod;invp[i] = 100ll * poly::invi[x] % mod;}for (int i = 1; i < n; i++) {cin >> w[i];pre[i] = (pre[i - 1] + w[i]) % mod;}for (int i = 1; i < n; i++) pre[i] = poly::quickpow(pre[i], mod - 2);for (int i = 0; i <= n; i++) fa[i] = fb[i] = 0;ea[0] = 1, eb[0] = 0;ea[1] = 1, eb[1] = (mod - c[0]) % mod;solve(0, n - 1);int ans = (mod - eb[n]) * poly::quickpow(ea[n], mod - 2) % mod;cout << (ans + mod) % mod << endl;}return 0;
}

1002、Boss Rush

题目链接:Problem - 7163 (hdu.edu.cn)

题意:

小Q有 n n n 个技能,每个技能点击后需要再过 t i t_i ti​ 时间才能点击其他技能,对于每个技能 i i i ,点击后的 l e n i len_i leni​ 时间内均会造成伤害 d i , j d_{i, j} di,j​ ,boss 的血量为 H H H ,问最早多久可以打败 boss

题解:

其实感觉题目有些问题,题解的意思似乎是不考虑顺序,这里的 n n n 比较小 ( n ≤ 15 ) (n\le 15) (n≤15) ,可以乱搞,二分+状压可以轻松做出

代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 20;
const int maxm = 1e5 + 5;
int t[maxm], len[maxm];
int d[maxn][maxm];
int tim[1 << maxn], dp[1 << maxn];
int n, hp;
bool check(int x) {memset(dp, -1, sizeof(dp));dp[0] = 0;for (int st = 0; st < 1 << n; st++) {int w = dp[st];if (w >= hp) return 1;if (w < 0 || tim[st] > x) continue;for (int i = 0; i < n; i++)if (!(st >> i & 1))if (tim[st] + len[i] - 1 <= x)dp[st | (1 << i)] = max(dp[st | (1 << i)], w + d[i][len[i] - 1]);elsedp[st | (1 << i)] = max(dp[st | (1 << i)], w + d[i][x - tim[st]]);}return 0;
}
signed main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);int _;cin >> _;while (_--) {cin >> n >> hp;int ans = -1;int l = 0, r = 0;for (int i = 0; i < n; i++) {cin >> t[i] >> len[i];r += t[i] + len[i];for (int j = 0; j < len[i]; j++) cin >> d[i][j];for (int j = 1; j < len[i]; j++) d[i][j] += d[i][j - 1];}for (int st = 1; st < (1 << n); st++)tim[st] = tim[st - (st & -st)] + t[__builtin_ctz(st & -st)];while (l <= r) {int mid = (l + r) >> 1;if (check(mid))r = (ans = mid) - 1;elsel = mid + 1;}cout << ans << endl;}return 0;
}

1003、Cyber Language

题目链接:Problem - 7164 (hdu.edu.cn)

题意:

给一堆句子,句子中包含几个单词,输出单词的首字母大写

题解:

~~

代码:

#include <bits/stdc++.h>
using namespace std;
string s;
int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);int _;cin >> _;getchar();while (_--) {getline(cin, s);int len = s.length();for (int i = 0; i < len; i++)if (i == 0 || s[i - 1] == ' ') cout << (char)toupper(s[i]);cout << endl;}return 0;
}

1008、Laser Alarm

题目链接: Problem - 7169 (hdu.edu.cn)
题意:

空间中有 n n n 条线段 n ≤ 50 n\le 50 n≤50 ,求一个与线段交点最多的平面

题解:

由于 n n n 比较小,所以可以乱搞,三点确定一个平面,所以我们枚举所有三点对即可,然后遍历计数
代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 55;
struct node {int x, y, z;node(int _x = 0, int _y = 0, int _z = 0) : x(_x), y(_y), z(_z) {}node operator-(const node& p) const {return node(x - p.x, y - p.y, z - p.z);}node operator*(const node& p) const {return node(y * p.z - z * p.y, z * p.x - x * p.z, x * p.y - y * p.x);}int operator^(const node& p) const { return x * p.x + y * p.y + z * p.z; }bool operator==(const node& p) const {return x == p.x && y == p.y && z == p.z;}
} p[maxn * 2];
int ptoplane(const node& a, const node& b, const node& c, const node& p) {return ((b - a) * (c - a)) ^ (p - a);
}
bool colinear(const node& a, const node& b, const node& p) {node t = (a - b) * (b - p);return !t.x && !t.y && !t.z;
}
int n;
int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);int _;cin >> _;while (_--) {cin >> n;for (int i = 1; i <= n * 2; i++) cin >> p[i].x >> p[i].y >> p[i].z;int ans = 1;for (int i = 1; i <= n * 2; i++) {for (int j = 1; j < i; j++) {if (p[i] == p[j]) continue;for (int k = 1; k < j; k++) {if (p[i] == p[j] || p[i] == p[k] || p[j] == p[k]) continue;if (colinear(p[i], p[j], p[k])) continue;int now = 0;for (int l = 1; l <= n; l++) {int x = ptoplane(p[i], p[j], p[k], p[l * 2 - 1]);int y = ptoplane(p[i], p[j], p[k], p[l * 2]);if (!x || !y || (x < 0 && y > 0) || (x > 0 && y < 0)) now++;}ans = max(ans, now);}int now = 0;for (int k = 1; k <= n; k++) {if (colinear(p[i], p[j], p[k * 2 - 1]) ||colinear(p[i], p[j], p[k * 2]))now++;}ans = max(ans, now);}}cout << ans << endl;}return 0;
}

1009、Package Delivery

题目链接:Problem - 7170 (hdu.edu.cn)

题意:

小Q有 n n n 个包裹,每个包裹都有一个区间时间,小Q必须在截至前拿走包裹,每次小Q最多可以拿 k k k 个,问小Q最少去邮局多少次

题解:

贪心即可,或者说尽量拖延就行,关注每个包裹的截至时间,在这个时间拿走包裹,顺便拿走其他截至时间早的就行。

下面这个算法看似是 O ( n 2 ) O(n^2) O(n2) 的,实际上线性时间内可以通过

代码:

#include <bits/stdc++.h>
#define pii pair<int, int>
using namespace std;
const int maxn = 1e5 + 5;
int n, k;
int ql[maxn], qr[maxn];
pii p[maxn];
bool vis[maxn];
int main() {ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);int _;cin >> _;while (_--) {memset(vis, 0, sizeof vis);priority_queue<pii, vector<pii>, greater<pii>> q;cin >> n >> k;for (int i = 1; i <= n; i++) {cin >> p[i].first >> p[i].second;ql[i] = qr[i] = i;}sort(ql + 1, ql + 1 + n,[](int a, int b) { return p[a].first < p[b].first; });sort(qr + 1, qr + 1 + n,[](int a, int b) { return p[a].second < p[b].second; });int res = 0;for (int i = 1, j = 1; i <= n; i++) {if (vis[qr[i]]) continue;while (j <= n && p[ql[j]].first <= p[qr[i]].second) {q.push({p[ql[j]].second, ql[j]});j++;}for (int l = 1; l <= k; l++) {if (q.empty()) break;vis[q.top().second] = true;q.pop();}res++;}cout << res << endl;}
}

1011、Taxi

题目链接:Problem - 7172 (hdu.edu.cn)

题意:

有 n n n 个城镇,每个城镇有一个坐标,小Q有张VIP卡,假如小Q从 ( x ′ , y ′ ) (x',y') (x′,y′) 前往 ( x k , y k ) (x_k,y_k) (xk​,yk​) ,那么VIP卡可以帮他报销 min ⁡ { ∣ x ′ − x k ∣ + ∣ y ′ − y k ∣ , ω k } \min \{|x'-x_k|+|y'-y_k|, \omega_k \} min{∣x′−xk​∣+∣y′−yk​∣,ωk​} 元。小Q想要去充分利用他的VIP卡,给出 q q q 个询问,每次询问给出一个坐标,要求找到VIP打折最多的一个地点。

题解:

这题用到了一些关于切比雪夫距离的一些技巧。没有 ω \omega ω 的限制的话,其实是一道很经典的问题。

max ⁡ { ∣ x ′ − x i ∣ + ∣ y ′ − y i ∣ } = max ⁡ { max ⁡ { x ′ − x i , − x ′ + x i } + max ⁡ { y ′ − y i , − y ′ + y i } } = max ⁡ { [ ( x ′ + y ′ ) + ( − x i − y i ) ] , [ ( x ′ − y ′ ) + ( − x i + y i ) ] , [ ( − x ′ + y ′ ) + ( x i − y i ) ] , [ ( − x ′ − y ′ ) + ( x i + y i ) ] } \max \{ |x'-x_i|+|y'-y_i| \} \\ =\max \{ \max\{x'-x_i,-x'+x_i\}+\max\{ y'-y_i, -y'+y_i\}\}\\=\max\{[(x'+y')+(-x_i-y_i)],[(x'-y')+(-x_i+y_i)],[(-x'+y')+(x_i-y_i)],[(-x'-y')+(x_i+y_i)]\} max{∣x′−xi​∣+∣y′−yi​∣}=max{max{x′−xi​,−x′+xi​}+max{y′−yi​,−y′+yi​}}=max{[(x′+y′)+(−xi​−yi​)],[(x′−y′)+(−xi​+yi​)],[(−x′+y′)+(xi​−yi​)],[(−x′−y′)+(xi​+yi​)]} 于是,记录 ( − x i − y i ) , ( − x i + y i ) , ( x i − y i ) , ( x i + y i ) (-x_i-y_i), \ (-x_i+y_i), \ (x_i-y_i), \ (x_i+y_i) (−xi​−yi​), (−xi​+yi​), (xi​−yi​), (xi​+yi​) 的最大值即可 O ( 1 ) O(1) O(1) 内查询,现考虑加入 ω \omega ω 的影响

先按 ω \omega ω 的大小对这些点排一个序,并记录一下区间后缀的距离最大值,进行分治二分即可

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f;
int n, q;
struct node {int x, y;int w;
} p[maxn];
int a[maxn], b[maxn], c[maxn], d[maxn];
int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);int _;cin >> _;while (_--) {cin >> n >> q;for (int i = 1; i <= n; i++) cin >> p[i].x >> p[i].y >> p[i].w;sort(p + 1, p + n + 1,[](const node &a, const node &b) { return a.w < b.w; });a[n + 1] = b[n + 1] = c[n + 1] = d[n + 1] = -inf;for (int i = n; i > 0; i--) {a[i] = max(a[i + 1], -p[i].x - p[i].y);b[i] = max(b[i + 1], -p[i].x + p[i].y);c[i] = max(c[i + 1], p[i].x - p[i].y);d[i] = max(d[i + 1], p[i].x + p[i].y);}while (q--) {int x, y;cin >> x >> y;int ans = 0;int l = 1, r = n, mid;while (l <= r) {mid = (l + r) >> 1;int tmp = max(max(x + y + a[mid], x - y + b[mid]),max(-x + y + c[mid], -x - y + d[mid]));if (p[mid].w < tmp) {l = mid + 1;ans = max(ans, p[mid].w);} else {r = mid - 1;ans = max(ans, tmp);}}cout << ans << endl;}}return 0;
}

1012、Two Permutations

题目链接:Problem - 7173 (hdu.edu.cn)

题意:

给出两个排列和一个序列,求两个排列组合成这个序列的方案数,两个排列的长均为 n n n ,序列长为 2 n 2n 2n ,每次总是将排列 P 、 Q P、Q P、Q 的最左端放进序列 S S S 的最右侧。 n ≤ 3 × 1 0 5 n\le 3\times 10^5 n≤3×105

题解:

很显然是一道 dp 题,那么该怎么去 dp 呢。表面上看,状态似乎是 n 2 n^2 n2 ,但实际上,有很多无效的状态,根据数据规模,其状态应该是 O ( n ) O(n) O(n) 级别的。设 d p i , j dp_{i, j} dpi,j​ 表示匹配至序列 S S S 的第 i i i 位, 并且最后一次匹配来源于 j = 1 / 2 j=1 / 2 j=1/2 ,那么有递归式: d p i , j = j u d g e 1 × d p i − 1 , j + j u d g e 2 × d p i − 1 , j ⊕ 1 dp_{i, j}=judge_1\times dp_{i-1, j}+judge_2\times dp_{i-1, j\oplus 1} dpi,j​=judge1​×dpi−1,j​+judge2​×dpi−1,j⊕1​

代码:

#include <bits/stdc++.h>
using namespace std;
const int mod = 998244353;
const int maxn = 3e5 + 5;
int p[maxn], q[maxn];
int s[maxn * 2];
int n;
int dp[2 * maxn][2];
int dfs(int i, int j, int flag) {// 匹配完 p_i, q_j 的方案数, flag 0 \ 1 代表从 p \ q 进入新匹配if (i <= 0 && j <= 0) return 1;if (dp[i + j][flag] != -1) return dp[i + j][flag];int ans = 0;if (p[i] == s[i + j] && i > 0) ans = (ans + dfs(i - 1, j, 0)) % mod;if (q[j] == s[i + j] && j > 0) ans = (ans + dfs(i, j - 1, 1)) % mod;return dp[i + j][flag] = ans;
}
int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);int _;cin >> _;while (_--) {memset(dp, -1, sizeof(dp));cin >> n;for (int i = 1; i <= n; i++) cin >> p[i];for (int i = 1; i <= n; i++) cin >> q[i];for (int i = 1; i <= 2 * n; i++) cin >> s[i];cout << dfs(n, n, 0) << endl;}return 0;
}

二、题目分析及解法(进阶题)

不会X

1004、Divide the Sweets

1005、Spanning Tree Game

1006、Dusk Moon

1007、Shallow Moon

1010、Range Reachability Query

2022杭电多校(三)相关推荐

  1. 2022杭电多校赛第八场

    2022杭电多校赛第八场 文章目录 2022杭电多校赛第八场 1004.Quel'Thalas 1001.Theramore 1011.Stormwind 1008.Orgrimmar 1005.Ir ...

  2. 2022杭电多校(十)

    2022杭电多校(十) 文章目录 2022杭电多校(十) 一.比赛小结 二.题目分析及解法(基础题) 1001.Winner Prediction 1003.Wavy Tree 1004.Averag ...

  3. 2022杭电多校(九)

    2022杭电多校(九) 文章目录 2022杭电多校(九) 一.比赛小结 二.题目分析及解法(基础题) 1001.Arithmetic Subsequence 1003.Fast Bubble Sort ...

  4. 2022杭电多校(二)

    2022杭电多校(二) 文章目录 2022杭电多校(二) 一.比赛小结 二.题目分析及解法(基础题) 1001.Static Query on Tree 1002.C++ to Python 1003 ...

  5. 2022杭电多校(四)

    2022杭电多校(四) 文章目录 2022杭电多校(四) 一.比赛小结 二.题目分析及解法(基础题) 1001.Link with Bracket Sequence II 1002.Link with ...

  6. 2022杭电多校(一)

    2022杭电多校(一) 文章目录 2022杭电多校(一) 一.比赛小结 二.题目分析及解法(基础题) 1001.String 1002.Dragon slayer 1003.BackPack 1004 ...

  7. 2022杭电多校(五)

    2022杭电多校(五) 文章目录 2022杭电多校(五) 一.比赛小结 二.题目分析及解法(基础题) 1003.Slipper 1006.BBQ 1007.Count Set 1010.Braggin ...

  8. 2022杭电多校第八场题解

    2022杭电多校第八场 Theramore(思维) 题意 给定一个01字符串,每次可以将一个奇数长度的区间翻转,求操作后字典序最小的字符串. 分析 翻转奇数长度的区间,元素位置的奇偶性不变,统计奇数位 ...

  9. 2022杭电多校九 1008-Shortest Path in GCD Graph(质因子+容斥)

    题目链接:杭电多校九 - Virtual Judge 题目: 样例输入: 6 2 4 5 3 6 样例输出: 1 1 2 2 题意:给定n个点的完全图,两个点之间的距离为他们的gcd,q次询问,每次询 ...

最新文章

  1. 打造全球最大规模 Kafka 集群,Uber 的多区域灾备实践
  2. sdut 2135 数据结构实验之队列一:排队买饭
  3. 【实用技能】通过sh脚本动态上传项目到github
  4. VTK:可视化算法之Stocks
  5. PPT图标的正确使用和插入与编辑形状
  6. 使用交叉存取得到更快推荐算法
  7. C++ int型与char型辨析
  8. TokenInsight:BTC多头比例延续上升,人气保持高位
  9. CListCtrl行高问题最终解决方法
  10. mysql 分表分库mycat_Mysql数据库之如何Mycat分表分库?
  11. 局域网电脑Sql2008 R2无法连接到localhost 解决方案
  12. 特征提取算法 知乎_对话 | 港科大教授权龙:为什么三维重建才是计算机视觉的灵魂?...
  13. 借助易宝实现Java版网上在线支付
  14. python小游戏课程设计报告_贪吃蛇游戏课程设计报告
  15. 嵌入式(二十七):arm
  16. 评估指标(Metric)(一)
  17. 隐私计算工程化之殇,为什么“久攻不破”?
  18. 空数组和null数组
  19. Nest中央空调控制器 舒适节能两手抓
  20. SemiBin宏基因组半监督分箱工具中GTDB数据的下载与配置

热门文章

  1. matlab——利用intlinprog和linprog函数求线性规划问题最优解
  2. HTML页面内Div内容添加滚动条
  3. 后台服务出现明显“变慢”诊断思路
  4. 永远的伊苏6流程攻略
  5. 51nod 1128 正整数分组 V2(二分)
  6. 隐私计算的应用研究与趋势展望(上)
  7. mysql查询scn号_深入了解SCN-select * from Mibon;-51CTO博客
  8. 松柏先生·每日一例:卖的不止是面包,而是一种生活方式
  9. 酒店怎么在抖音宣传推广?
  10. Docker安装+Kafka的简易使用+代码实现