斜率优化dp,莫队 + 线段树,权值线段树 + 线段树合并,数位dp
# A. 核酸检测
看了很久才发现是斜率优化……那么就是一个斜率优化板题。
先看暴力 ,设 表示计算到 位置且在 上放一名医护人员的最小花费,转移的时候枚举上一名医护人员的位置。
化简一下就可以斜率优化了(自己推吧,懒得打了QwQ)。
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
using namespace std;
namespace IO{
inline int read(){
int x = 0;
char ch = getchar();
while(!isdigit(ch)) ch = getchar();
while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x;
}
template <typename T> inline void write(T x){
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
}
}
using namespace IO;
const int N = 1e6 + 10;
int n, ans;
int a[N], f[N];
int q[N];
inline double slope(int i, int j){
return (Y(i) - Y(j)) / (X(i) - X(j));
}
signed main(){
n = read();
for(int i = 1; i <= n; ++i) a[i] = read();
int l = 1, r = 1;
for(int i = 1; i <= n; ++i){
while(l < r && slope(q[l], q[l + 1]) < i) l++;
f[i] = f[q[l]] + (i - q[l]) * (i - q[l] - 1) / 2 + a[i];
while(l < r && slope(q[r - 1], q[r]) > slope(q[r], i)) r--;
q[++r] = i;
}
write(f[n]), puts("");
return 0;
}
# B. 排列
这题也比较水。
开个值域线段树维护数字是否出现,这是个非常经典的东西,就维护 三个值就好。
外面再套一个莫队就可以做到 ,不是很卡。
是在不行的话莫队排序的时候加个奇偶优化即可。
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
using namespace std;
namespace IO{
inline int read(){
int x = 0;
char ch = getchar();
while(!isdigit(ch)) ch = getchar();
while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x;
}
template <typename T> inline void write(T x){
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
}
}
using namespace IO;
const int N = 5e4 + 10;
int n, m, B, tot;
int a[N], be[N], L[N], R[N];
int ans[N];
struct node{
int l, r, id;
inline bool operator < (const node &b) const{
return be[l] != be[b.l] ? be[l] < be[b.l] : (be[l] & 1 ? r < b.r : r > b.r);
}
}q[N];
struct Tree{
int mxl, mxr, mx, len;
}t[N << 2];
inline void pushup(int rt){
t[rt].mxl = t[ls].mxl, t[rt].mxr = t[rs].mxr;
if(t[ls].mxl == t[ls].len) t[rt].mxl = t[ls].len + t[rs].mxl;
if(t[rs].mxr == t[rs].len) t[rt].mxr = t[rs].len + t[ls].mxr;
t[rt].mx = max(max(t[ls].mx, t[rs].mx), t[ls].mxr + t[rs].mxl);
}
inline void build(int l, int r, int rt){
t[rt].len = r - l + 1;
if(l == r) return;
build(l, mid, ls), build(mid + 1, r, rs);
pushup(rt);
}
inline void update(int x, int k, int l, int r, int rt){
if(l == r) return t[rt].mx = t[rt].mxl = t[rt].mxr = k, void();
if(x <= mid) update(x, k, l, mid, ls);
else update(x, k, mid + 1, r, rs);
pushup(rt);
}
inline void add(int x){
update(a[x], 1, 1, n, 1);
}
inline void del(int x){
update(a[x], 0, 1, n, 1);
}
signed main(){
n = read(), m = read(), B = sqrt(n);
for(int i = 1; i <= n; ++i) a[i] = read(), be[i] = (i - 1) / B + 1;
for(int i = 1; i <= m; ++i)
q[i] = (node){read(), read(), i};
sort(q + 1, q + 1 + m);
build(1, n, 1);
int l = 1, r = 0;
for(int i = 1; i <= m; ++i){
while(l > q[i].l) add(--l);
while(r < q[i].r) add(++r);
while(l < q[i].l) del(l++);
while(r > q[i].r) del(r--);
ans[q[i].id] = t[1].mx;
}
for(int i = 1; i <= m; ++i) write(ans[i]), puts("");
return 0;
}
# C. ROT-Tree Rotations
建权值线段树,然后线段树合并。
合并时计算左右子树在前在后时分别的逆序对数,然后取较小的即可。
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
using namespace std;
namespace IO{
inline int read(){
int x = 0, f = 1;
char ch = getchar();
while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
template <typename T> inline void write(T x){
if(x < 0) putchar('-'), x = -x;
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
}
}
using namespace IO;
const int N = 2e5 + 10;
int n;
ll res1, res2, ans;
int tot;
int siz[N << 5], ls[N << 5], rs[N << 5];
inline int update(int k, int l, int r){
int p = ++tot; siz[p]++;
if(l == r) return p;
int mid = (l + r) >> 1;
if(k <= mid) ls[p] = update(k, l, mid);
else rs[p] = update(k, mid + 1, r);
return p;
}
inline int merge(int u, int v, int l, int r){
if(!u || !v) return u | v;
if(l == r) return siz[u] += siz[v], u;
res1 += 1ll * siz[rs[u]] * siz[ls[v]];
res2 += 1ll * siz[ls[u]] * siz[rs[v]];
int mid = (l + r) >> 1;
ls[u] = merge(ls[u], ls[v], l, mid);
rs[u] = merge(rs[u], rs[v], mid + 1, r);
siz[u] = siz[ls[u]] + siz[rs[u]];
return u;
}
inline int dfs(){
int k = read(), pos;
if(!k){
int ls = dfs(), rs = dfs(); res1 = res2 = 0;
pos = merge(ls, rs, 1, n), ans += min(res1, res2);
}else pos = update(k, 1, n);
return pos;
}
signed main(){
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
n = read();
dfs();
write(ans), puts("");
return 0;
}
# D. 计算
数位 。
先通过 预处理出 的 数组,方便后面转移。
设 表示计算到 的第 位,匹配到 的第 位时后面的答案。
转移时枚举第 位为 ,那么贡献为:。
最后输出时要减去 ,即减 1。
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
using namespace std;
namespace IO{
inline int read(){
int x = 0, f = 1;
char ch = getchar();
while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x * f;
}
template <typename T> inline void write(T x){
if(x < 0) putchar('-'), x = -x;
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
}
}
using namespace IO;
const int N = 15;
int n, m;
int b[N], lb, num[N], len;
int nxt[N], pw[N];
double dp[N][N];
inline void init(){
for(int i = 0; i <= 13; ++i)
for(int j = 0; j <= 13; ++j) dp[i][j] = -1;
pw[0] = 1;
for(int i = 1; i <= 10; ++i) pw[i] = pw[i - 1] * 10;
int x = m;
while(x) b[++lb] = x % 10, x /= 10;
reverse(b + 1, b + 1 + lb);
x = n;
while(x) num[++len] = x % 10, x /= 10;
reverse(num + 1, num + 1 + len);
for(int i = 2, j = 0; i <= lb; ++i){
while(j && b[i] != b[j + 1]) j = nxt[j];
if(b[i] == b[j + 1]) j++;
nxt[i] = j;
}
}
inline int get_nxt(int i, int j){
while(j && i != b[j + 1]) j = nxt[j];
if(i == b[j + 1]) j++;
return j;
}
inline double dfs(int pos, int mat, bool lim){
if(mat == lb) return 0;
if(pos == len + 1) return 1;
if(!lim && dp[pos][mat] != -1) return dp[pos][mat];
double res = 0, up = lim ? num[pos] : 9;
for(int i = 0; i <= up; ++i)
res += dfs(pos + 1, get_nxt(i, mat), (lim & (i == up))) * exp(1.0 * i * pw[len - pos] / n);
if(!lim) dp[pos][mat] = res;
return res;
}
signed main(){
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
n = read(), m = read(), init();
printf("%.3lf\n", dfs(1, 0, 1) - 1);
return 0;
}