好吧,其实只补了E题,先写E题解吧,训练时脑袋不清醒读错题,导致没能切掉E,思路其实很好想,码量也不大
update:
C. Insertion Sort
题意:问有多少个排列, 排列的前k个元素排序后,整个排列的最长上升子序列长度为n-1
解法:第一步:设 为长度为 的排列中,一共有 种排列 长度恰好为 ,很显然,我们可以在所有长度为 且 长度为 的排列最后位置插入一个 ,那么 ,此外,当第倒数第二个位置上为 时,最后一个位置可以选 个数,且前 个数必须单调递增,那我门可以在倒数第二个位置后面插入 ,那么 ,对于排列: ,除了最后一个位置,我们都可以插入 , 。
第二步:当前 个数最大值为 时,不难发现合法排列数: ,当前 个数最大值为 时,我们枚举前 个数不存在哪个数,然后不存在的这个数可以放置后 个位置,那么排列数: ,当前 个数最大值大于 时,后面 个数必须递增的放置,合法排列数都是
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 55;
ll p[maxn], inv[maxn], mod;
int d[maxn];
void add(int &x, int y) {
x += y;
if (x >= mod)
x -= mod;
if (x < 0)
x += mod;
}
ll ksm(ll x, int y) {
ll res = 1;
while (y) {
if (y & 1)
res = res * x % mod;
x = x * x % mod;
y /= 2;
}
return res;
}
void init(int n) {
p[0] = inv[0] = 1;
for (int i = 1; i <= n; i++) {
p[i] = 1ll * i * p[i - 1] % mod;
inv[i] = ksm(p[i], mod - 2);
}
}
ll gao(int n) {
if (n == 2)
return 1;
d[n] = gao(n - 1);
add(d[n], n - 1);
add(d[n], n - 2);
return d[n];
}
int main() {
int T, Case = 0;
scanf("%d", &T);
while (T--) {
int n, k;
scanf("%d%d%d", &n, &k, &mod);
init(n);
printf("Case #%d: ", ++Case);
if (k >= n - 1) {
printf("%d\n", p[n]);
continue;
}
memset(d, 0, sizeof(d));
ll tmp = gao(n - k) + 1;
ll ans = p[k] * tmp % mod + p[k] * k % mod * (n - k) % mod + p[k] * (n - (k + 1)) % mod;
printf("%lld\n", ans % mod);
}
}
题意:有n个人,每个人有坐标和宗族,有三种操作,分别是修改某个人坐标,修改某个人宗族,查询第 l 个人到第 r 个人中属于不同宗族的两个人的最大曼哈顿距离
解法:线段树没法维护曼哈顿距离,但是我们知道曼哈顿距离可以通过简单变换成切比雪夫距离,我们变换后只要维护最大最小的x坐标,最大最小的y坐标,每次查询查mx - mn即可,但是有问题,要求不同宗族,因此我们可以维护个次大x坐标,要求次大的坐标必须所属的宗族与最大所属宗族不同,次小同理,这样的话,假设mx和mn属于同一宗族,我们还可以通过次大次小来求答案
#include<bits/stdc++.h>
#define ll long long
#define pi pair<ll, int>
#define mk make_pair
#define fi first
#define se second
#define ls o * 2
#define rs o * 2 + 1
#define mid (l + r) / 2
using namespace std;
const int maxn = 1e5 + 10;
ll inf = 1e18;
struct seg {
pi mx, mn, mx2, mn2;
seg operator+(const seg& t) const {
seg tmp;
tmp.mx2 = max(mx2, t.mx2);
tmp.mx = max(mx, t.mx);
if (t.mx.se != tmp.mx.se && t.mx > tmp.mx2)
tmp.mx2 = t.mx;
if (mx.se != tmp.mx.se && mx > tmp.mx2)
tmp.mx2 = mx;
tmp.mn = min(mn, t.mn);
tmp.mn2 = min(mn2, t.mn2);
if (t.mn.se != tmp.mn.se && t.mn < tmp.mn2)
tmp.mn2 = t.mn;
if (mn.se != tmp.mn.se && mn < tmp.mn2)
tmp.mn2 = mn;
return tmp;
}
} cat[maxn * 4], peach[maxn * 4];
ll x[maxn], y[maxn];
int c[maxn], n;
void up(int o, int l, int r, int k) {
if (l == r) {
cat[o].mx = cat[o].mn = mk(x[l], c[l]);
peach[o].mx = peach[o].mn = mk(y[l], c[l]);
cat[o].mx2 = peach[o].mx2 = mk(-inf, 0);
cat[o].mn2 = peach[o].mn2 = mk(inf, 0);
return;
}
if (k <= mid)
up(ls, l, mid, k);
else
up(rs, mid + 1, r, k);
cat[o] = cat[ls] + cat[rs];
peach[o] = peach[ls] + peach[rs];
}
seg qu(int o, int l, int r, int ql, int qr, int opt) {
if (l >= ql && r <= qr) {
if (opt == 1)
return cat[o];
return peach[o];
}
if (qr <= mid)
return qu(ls, l, mid, ql, qr, opt);
else if (ql > mid)
return qu(rs, mid + 1, r, ql, qr, opt);
return qu(ls, l, mid, ql, qr, opt) + qu(rs, mid + 1, r, ql, qr, opt);
}
ll gao(int l, int r, int opt) {
seg tmp = qu(1, 1, n, l, r, opt);
if (tmp.mx.se != tmp.mn.se)
return max(0ll, tmp.mx.fi - tmp.mn.fi);
return max(0ll, max(tmp.mx.fi - tmp.mn2.fi, tmp.mx2.fi - tmp.mn.fi));
}
int main() {
int T, Case = 0;
scanf("%d", &T);
while (T--) {
printf("Case #%d:\n", ++Case);
int m, opt, tx, ty, k;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%lld%lld%d", &tx, &ty, &c[i]);
x[i] = tx + ty;
y[i] = tx - ty;
up(1, 1, n, i);
}
while (m--) {
scanf("%d", &opt);
if (opt == 1) {
scanf("%d%d%d", &k, &tx, &ty);
x[k] += tx + ty;
y[k] += tx - ty;
up(1, 1, n, k);
}
else {
scanf("%d%d", &tx, &ty);
if (opt == 2) {
c[tx] = ty;
up(1, 1, n, tx);
}
else
printf("%lld\n", max(gao(tx, ty, 1), gao(tx, ty, 2)));
}
}
}
}