洛谷
有 \(n\) 个廊桥,\(m_1\) 个一类飞机、\(m_2\) 个二类飞机,贪心原则分配廊桥,问做多能给多少飞机分上廊桥。
设 \(f_i\) 表示分 \(i\) 个廊桥给一类飞机的最多的飞机,\(g_i\) 表示分 \(i\) 个廊桥给二类飞机的最多的飞机。题目就转化为求最大的 \(f_i+g_{n-i}\)
考场上想的是三分,但是用脚趾都能造出一个卡三分的数据。
实际上可以发现一个飞机只要在 \(x\) 个廊桥的情况下能分配到,那么 \([x,\infty]\) 都能。先用堆求出每个飞机能分配最少需要的廊桥,然后解法显然。
const int N = 1e5 + 10; inline ll Read() { ll x = 0, f = 1; char c = getchar(); while (c != '-' && (c < '0' || c > '9')) c = getchar(); if (c == '-') f = -f, c = getchar(); while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar(); return x * f; } int n, m1, m2; struct node { int l, r; bool operator < (node a) const { return l < a.l; } } a[N], b[N]; int pa[N], pb[N], ca[N], cb[N]; priority_queue<int, vector<int>, greater<int> > q; struct pQueue { int val, id; bool operator < (const pQueue &a) const { return val > a.val; } }; priority_queue<pQueue> qr; int suma = 0, sumb = 0, ans; int main() { // freopen(".in", "r", stdin); // freopen(".out", "w", stdout); n = Read(), m1 = Read(), m2 = Read(); for (int i = 1; i <= m1; i++) a[i].l = Read(), a[i].r = Read(); for (int i = 1; i <= m2; i++) b[i].l = Read(), b[i].r = Read(); sort (a + 1, a + 1 + m1); sort (b + 1, b + 1 + m2); for (int i = 1; i <= n; i++) q.push(i); for (int i = 1; i <= m1; i++) { if (!qr.empty()) for (pQueue j = qr.top(); j.val < a[i].l && !qr.empty(); ) { qr.pop(); q.push(j.id); if (!qr.empty()) j = qr.top(); } if (!q.empty()) { pa[i] = q.top(); ca[pa[i]]++; qr.push((pQueue){a[i].r, pa[i]}); q.pop(); } } for (; !q.empty(); q.pop()); for (; !qr.empty(); qr.pop()); for (int i = 1; i <= n; i++) q.push(i); for (int i = 1; i <= m2; i++) { if (!qr.empty()) for (pQueue j = qr.top(); j.val < b[i].l && !qr.empty(); ) { qr.pop(); q.push(j.id); if (!qr.empty()) j = qr.top(); } if (!q.empty()) { pb[i] = q.top(); cb[pb[i]]++; sumb++; qr.push((pQueue){b[i].r, pb[i]}); q.pop(); } } for (int i = 0; i <= n; i++) { suma += ca[i], sumb -= cb[n - i + 1]; ans = max(ans, suma + sumb); } printf ("%d\n", ans); return 0; }
洛谷
有一个很强的状态 \(f_{l,r,[0,5]}\) 表示在区间 \([l,r]\) 中字符串属于 全部是*
、左右为匹配的括号
、左括右*
、左右不一定匹配的括号
、左*右括
,左右为*
。
这个状态设法不用判重太强了。
转移见代码。
const int N = 510; const ll mod = 1e9 + 7; inline ll Read() { ll x = 0, f = 1; char c = getchar(); while (c != '-' && (c < '0' || c > '9')) c = getchar(); if (c == '-') f = -f, c = getchar(); while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar(); return x * f; } int n, m; char s[N]; ll f[N][N][10]; int main() { // freopen(".in", "r", stdin); // freopen(".out", "w", stdout); n = Read(), m = Read(); scanf ("%s", s + 1); for (int i = 1; i <= n; i++) f[i][i - 1][0] = 1; for (int len = 1; len <= n; len++) for (int l = 1; l + len - 1 <= n; l++) { int r = l + len - 1; if (len <= m) f[l][r][0] = f[l][r - 1][0] * (s[r] == '?' || s[r] == '*'); if (len >= 2) { if ((s[l] == '(' || s[l] == '?') && (s[r] == ')' || s[r] == '?')) f[l][r][1] = (f[l + 1][r - 1][0] + f[l + 1][r - 1][2] + f[l + 1][r - 1][3] + f[l + 1][r - 1][4]) % mod; for (int k = l; k < r; k++) (f[l][r][2] += f[l][k][3] * f[k + 1][r][0] % mod) %= mod, (f[l][r][3] += (f[l][k][2] + f[l][k][3]) % mod * f[k + 1][r][1] % mod) %= mod, (f[l][r][4] += (f[l][k][4] + f[l][k][5]) % mod * f[k + 1][r][1] % mod) %= mod, (f[l][r][5] += f[l][k][4] * f[k + 1][r][0] % mod) %= mod; } f[l][r][3] = (f[l][r][3] + f[l][r][1]) % mod; f[l][r][5] = (f[l][r][5] + f[l][r][0]) % mod; } printf ("%lld\n", f[1][n][3]); return 0; }
洛谷
你看它像个栈,那就把它当栈做。没了。
const int N = 1e6 + 10; inline ll Read() { ll x = 0, f = 1; char c = getchar(); while (c != '-' && (c < '0' || c > '9')) c = getchar(); if (c == '-') f = -f, c = getchar(); while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar(); return x * f; } int t, n, sm, em; int a[N]; char b[N]; int top1, bot1, top2, bot2; bool Work(int opt = 1) { int pos = 0; top1 = top2 = 0, bot1 = bot2 = 1; if (opt) { for (int i = 2; i <= 2 * n; i++) if (a[i] == a[1]) { pos = i; break; } bot1 = 2, top1 = pos - 1, bot2 = pos + 1, top2 = 2 * n; } else { for (int i = 2 * n - 1; i; i--) if (a[i] == a[2 * n]) { pos = i; break; } bot1 = 1, top1 = pos - 1, bot2 = pos + 1, top2 = 2 * n - 1; } bool flag = 0; for (int i = 1; i < n; i++) { if (bot1 <= top1 && (a[top1] == a[bot1] && bot1 < top1 || a[bot1] == a[bot2] && bot2 <= top2)) { if (bot1 < top1 && a[top1] == a[bot1]) top1--, bot1++, b[++sm] = 'L', b[--em] = 'L'; else bot1++, bot2++, b[++sm] = 'L', b[--em] = 'R'; } else { if (bot2 <= top2 && (a[top2] == a[top1] && bot1 <= top1 || a[top2] == a[bot2] && bot2 < top2)) { if (bot2 < top2 && a[top2] == a[bot2]) top2--, bot2++, b[++sm] = 'R', b[--em] = 'R'; else top2--, top1--, b[++sm] = 'R', b[--em] = 'L'; } else return 0; } } printf ("%s\n", b + 1); return 1; } int main() { // freopen(".in", "r", stdin); // freopen(".out", "w", stdout); for (t = Read(); t--; ) { n = Read(); for (int i = 1; i <= 2 * n; i++) a[i] = Read(); for (int i = 1; i <= 2 * n + 1; i++) b[i] = 0; b[sm = 1] = b[em = 2 * n] = 'L'; if (!Work()) { for (int i = 1; i <= 2 * n + 1; i++) b[i] = 0; b[sm = 1] = 'R', b[em = 2 * n] = 'L'; if (!Work(0)) printf ("-1\n"); } } return 0; }
咕咕咕。