Educational Codeforces Round 69 题解

题目编号 A B C D E F
完成情况 -

D. Yet Another Subarray Problem

一个子数组的价值为:

\[\sum_{i=l}^{r} a[i] - k\lceil{\frac{r-l+1}{m}}\rceil
\]

求解其最大值。子数组可以为空,此时价值为0.

\(r-l+1\)自然是子数组的长度\(len\),可以发现每当\(len\)增加\(m\)后,\(\lceil{\frac{r-l+1}{m}}\rceil\)会增加1。也就是说,子数组的权值受到长度的影响。\(dp[len][n]\)显然是不行的。实际上转移的时候,\(dp[len][n]\)从\(dp[len-1][n-1]\)转移过来,我们真正关心的是\(len\)能否被\(m\)整除,从而要多减一个\(k\)。于是只需要存储\(len mod m\)的余数就可以了。

\[dp[i][j]:include\ a[i]\ and\ len\ mod\ m\ =\ j
\]

\[if\ m\ ==\ 0\ OR\ j\ ==\ 1\ \ \ dp[i][j]\ =\ max\{dp[i\ -\ 1][0],\ 0\}\ +a[i]\ -\ k
\]

\[else\ if\ j==0\ \ \ dp[i][j]\ =\ dp[i-1][m - 1]\ +\ a[i]
\]

\[else\ \ \ dp[i][j]=dp[i-1][j-1]+a[i]
\]

一定要留心\(m=1\)的情况!单独考虑

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath> long long max(long long a, long long b){return a > b ? a : b;}
long long min(long long a, long long b){return a < b ? a : b;}
void swap(long long &a, long long &b){long long tmp = a;a = b;b = tmp;}
long long lowbit(long long &x){return x & (-x);}
void read(long long &x)
{
x = 0;char ch = getchar(), c = ch;
while(ch < '0' || ch > '9') c = ch, ch = getchar();
while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
if(c == '-') x = -x;
} const long long INF = 0x3f3f3f3f3f3f3f3f;
const long long MAXN = 300000 + 10;
const long long MAXM = 10; long long dp[MAXN][MAXM + 10], n, m, k, a[MAXN];
//dp[i][j]表示以i为结尾或者空串,长度余数为j的最大值
//dp[i][j] = dp[i - 1][j - 1] + a[i]
//dp[i][j] = dp[i - 1][j - 1] + a[i] - k int main()
{
read(n), read(m), read(k);
long long ans = 0;
for(long long i = 1;i <= n;++ i) read(a[i]); for(int i = 0;i <= n;++ i)
for(int j = 0;j < m;++ j)
dp[i][j] = -INF; for(long long i = 1;i <= n;++ i)
for(long long j = 0;j < m;++ j)
{
if(j == 1 || m == 1)
dp[i][j] = max(dp[i - 1][0], 0) + a[i] - k;
else if(j == 0)
dp[i][j] = dp[i - 1][m - 1] + a[i];
else
dp[i][j] = dp[i - 1][j - 1] + a[i];
ans = max(ans, dp[i][j]);
}
printf("%I64d", ans);
return 0;
}

E. Culture Code

有一些套娃,每个套娃都有\(in_i\)和\(out_i\)两个属性,只有\(in_i\ \geq\ out_j\),套娃\(j\)才能套在\(i\)的里面。一个相互嵌套的套娃集合的额外值定义为:

\[in_i\ +\ (in_{i+1}\ -out_{i})\ +\ (in_{i+2}\ -out_{i+1})\ +\ (in_{i+3}\ -out_{i+2})\ +\ \cdots\ +\ (in_{j}\ -out_{j-1})\
\]

一个套娃集合为极大集合,当且仅当不能再套在里面或外面任意另一个套娃。

求套娃极大集合的最小额外值的方案数

将套娃按照\(in\)降序排序

\(dp[0][i]\)表示前i个套娃,第\(i\)个套娃在最里面的最小额外值

\(dp[1][i]\)表示上面这个最小额外值的方案

\[dp[0][i]\ =\ min\{dp[0][j]\}\ -\ (out[i]\ -\ in[i])\
\]

相当于把第\(j\)个下面塞上\(i\),额外值减小。要求$in[j] \geq\ out[i]\ $ 直接二分就能找到合法区间\(1~x\),用线段树维护前缀最小和最小的个数。

其实也不用二分,在线段树询问操作中实现二分即可。

求最小的过程保证了对于前\(i\)个,第\(i\)个是极大集合。证明方法采用数学归纳法。第一个本身就是极大集合,从第二个开始,对于第\(i个\),因为里面不能再套,外面在\(dp\)后已经套过一个\(j\),\(j\)是前\(j\)个中的最大集合(假设条件),而\(j+1~i-1\)中的\(in\)小于等于\(in[j]\),因而小于\(out[j]\),也不能再套了

最后计算结果时,把所有\(dp[0][i]==min\)的\(dp[1][i]\)累加。能证明最小的\(dp[0][i]\)一定是极大集合,首先放在\(i\)后面的只能往它下面套,会让答案减小,后面的不能

再套了;前面的能不能套再套,证明同上

初始状态:\(dp[0][1] = in[1]\)

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath> long long max(long long a, long long b){return a > b ? a : b;}
long long min(long long a, long long b){return a < b ? a : b;}
void swap(long long &a, long long &b){long long tmp = a;a = b;b = tmp;}
long long lowbit(long long &x){return x & (-x);}
void read(long long &x)
{
x = 0;char ch = getchar(), c = ch;
while(ch < '0' || ch > '9') c = ch, ch = getchar();
while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
if(c == '-') x = -x;
} const long long INF = 0x3f3f3f3f3f3f3f3f;
const long long MAXN = 200000 + 10;
const long long MOD = 1e9 + 7; long long n, in[MAXN], out[MAXN], id[MAXN]; bool cmp(long long a, long long b)
{
return in[a] > in[b];
} struct Node
{
long long cnt, mi;
}node[MAXN << 2]; Node merge(Node& a, Node& b)
{
Node re;
if(a.mi == b.mi)
re.mi = a.mi,
re.cnt = a.cnt + b.cnt,
re.cnt >= MOD ? re.cnt -= MOD : 0;
else if(a.mi < b.mi)
re = a;
else
re = b;
return re;
} void pushup(long long o)
{
node[o] = merge(node[o << 1], node[o << 1 | 1]);
return ;
} void build(long long o = 1, long long l = 1, long long r = n)
{
if(l == r)
{
node[o].mi = INF, node[o].cnt = 0;
return ;
}
long long mid = (l + r) >> 1;
build(o << 1, l, mid);
build(o << 1 | 1, mid + 1, r);
pushup(o);
} //在p位置更新最小值为x,方案数为y
void modify(long long p, long long x, long long y, long long o = 1, long long l = 1, long long r = n)
{
if(l == r)
{
if(node[o].mi == x) node[o].cnt += y;
else node[o].mi = x, node[o].cnt = y;
return ;
}
long long mid = (l + r) >> 1;
if(p <= mid) modify(p, x, y, o << 1, l, mid);
else modify(p, x, y, o << 1 | 1, mid + 1, r);
pushup(o);
return ;
} //1到最后一个大于等于x的位置
Node ask(long long x, long long rr, long long o = 1, long long l = 1, long long r = n)
{
if(in[id[r]] >= x && rr >= r) return node[o];
long long mid = (l + r) >> 1;
Node a, b;
a.mi = INF, b.mi = INF;
if(in[id[l]] >= x) a = ask(x, rr, o << 1, l, mid);
if(in[id[mid + 1]] >= x && rr > mid) b = ask(x, rr, o << 1 | 1, mid + 1, r);
return merge(a, b);
} Node dp[MAXN];
long long mi = INF, ans = 0; int main()
{
read(n);
for(long long i = 1;i <= n;++ i)
read(out[i]), read(in[i]), id[i] = i;
std::sort(id + 1, id + 1 + n, cmp);
build();
modify(1, in[id[1]], 1);
dp[1].mi = in[id[1]], dp[1].cnt = 1;
for(long long i = 2;i <= n;++ i)
{
dp[i] = ask(out[id[i]], i - 1);
if(dp[i].mi == INF) dp[i].mi = in[id[i]], dp[i].cnt = 1;
else dp[i].mi -= out[id[i]] - in[id[i]];
modify(i, dp[i].mi, dp[i].cnt);
}
for(long long i = 1;i <= n;++ i)
mi = min(mi, dp[i].mi);
for(long long i = 1;i <= n;++ i)
if(dp[i].mi == mi)
ans += dp[i].cnt,
ans >= MOD ? ans -= MOD : 0;
printf("%I64d", ans);
return 0;
}

---恢复内容结束---

#Educational Codeforces Round 69 题解

题目编号 A B C D E F
完成情况 -

D. Yet Another Subarray Problem

一个子数组的价值为:

\[\sum_{i=l}^{r} a[i] - k\lceil{\frac{r-l+1}{m}}\rceil
\]

求解其最大值。子数组可以为空,此时价值为0.

\(r-l+1\)自然是子数组的长度\(len\),可以发现每当\(len\)增加\(m\)后,\(\lceil{\frac{r-l+1}{m}}\rceil\)会增加1。也就是说,子数组的权值受到长度的影响。\(dp[len][n]\)显然是不行的。实际上转移的时候,\(dp[len][n]\)从\(dp[len-1][n-1]\)转移过来,我们真正关心的是\(len\)能否被\(m\)整除,从而要多减一个\(k\)。于是只需要存储\(len mod m\)的余数就可以了。

\[dp[i][j]:include\ a[i]\ and\ len\ mod\ m\ =\ j
\]

\[if\ j==0\ dp[i][j]\ =\ max \{ dp[i-1][m-1],0 \} +a[i]-k \}
\]

\[else\ dp[i][j]=dp[i-1][j-1]+a[i]
\]

初始状态:因为\(dp\)中有很多不合题意的量,我们不能用这些量去进行转移,于是初始全部赋值为\(-INF\)。\(dp[1][0]\)和\(dp[1][1]\)是唯两个满足条件的第一维是1的量,为了让他们赋值正确,考虑让dp[0][m-1]=0

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath> long long max(long long a, long long b){return a > b ? a : b;}
long long min(long long a, long long b){return a < b ? a : b;}
void swap(long long &a, long long &b){long long tmp = a;a = b;b = tmp;}
long long lowbit(long long &x){return x & (-x);}
void read(long long &x)
{
x = 0;char ch = getchar(), c = ch;
while(ch < '0' || ch > '9') c = ch, ch = getchar();
while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
if(c == '-') x = -x;
} const long long INF = 0x3f3f3f3f3f3f3f3f;
const long long MAXN = 300000 + 10;
const long long MAXM = 10; long long dp[MAXN][MAXM + 10], n, m, k, a[MAXN];
//dp[i][j]表示以i为结尾或者空串,长度余数为j的最大值
//dp[i][j] = dp[i - 1][j - 1] + a[i]
//dp[i][j] = dp[i - 1][j - 1] + a[i] - k if j == 0 int main()
{
read(n), read(m), read(k);
long long ans = 0;
for(long long i = 1;i <= n;++ i) read(a[i]); for(int i = 0;i <= n;++ i)
for(int j = 0;j < m;++ j)
dp[i][j] = -INF;
dp[0][m - 1] = 0; for(long long i = 1;i <= n;++ i)
for(long long j = 0;j < m;++ j)
{
if(j == 0)
dp[i][j] = max(dp[i - 1][m - 1] + a[i] , a[i]) - k;
else
dp[i][j] = dp[i - 1][j - 1] + a[i];
ans = max(ans, dp[i][j]);
}
printf("%I64d", ans);
return 0;
}

Educational Codeforces Round 69 D E的更多相关文章

  1. Educational Codeforces Round 69 (Rated for Div. 2) E. Culture Code

    Educational Codeforces Round 69 (Rated for Div. 2) E. Culture Code 题目链接 题意: 给出\(n\)个俄罗斯套娃,每个套娃都有一个\( ...

  2. Educational Codeforces Round 69 D. Yet Another Subarray Problem

    Educational Codeforces Round 69 (Rated for Div. 2) D. Yet Another Subarray Problem 题目链接 题意: 求\(\sum_ ...

  3. Educational Codeforces Round 69 (Rated for Div. 2)

                                                                                                  A. DIY ...

  4. Educational Codeforces Round 69 (Rated for Div. 2) D. Yet Another Subarray Problem 背包dp

    D. Yet Another Subarray Problem You are given an array \(a_1, a_2, \dots , a_n\) and two integers \( ...

  5. Educational Codeforces Round 69 (Rated for Div. 2) C. Array Splitting 水题

    C. Array Splitting You are given a sorted array

  6. Educational Codeforces Round 69

    目录 Contest Info Solutions A. DIY Wooden Ladder B. Pillars C. Array Splitting D. Yet Another Subarray ...

  7. Educational Codeforces Round 69 (Rated for Div. 2) A~D Sloution

    A. DIY Wooden Ladder 题意:有一些不能切的木板,每个都有一个长度,要做一个梯子,求梯子的最大台阶数 做梯子的木板分为两种,两边的两条木板和中间的若干条台阶木板 台阶数为 $k$ 的 ...

  8. Educational Codeforces Round 69 E - Culture Code (最短路计数+线段树优化建图)

    题意:有n个空心物品,每个物品有外部体积outi和内部体积ini,如果ini>outj,那么j就可以套在i里面.现在我们要选出n个物品的一个子集,这个子集内的k个物品全部套在一起,且剩下的物品都 ...

  9. Educational Codeforces Round 69 (Rated for Div. 2)D(DP,思维)

    #include<bits/stdc++.h>using namespace std;int a[300007];long long sum[300007],tmp[300007],mx[ ...

随机推荐

  1. hive的复合数据类型

    hive中的复合数据类型 Array array中的数据为相同类型,例如,假如array A中元素['a','b','c'],则A[1]的值为'b' 数据结构如下: zhangsan beijing, ...

  2. NX二次开发-UFUN修剪体UF_MODL_trim_body

    1 NX11+VS2013 2 3 4 #include <uf.h> 5 #include <uf_modl.h> 6 7 8 UF_initialize(); 9 10 / ...

  3. NX二次开发-获取切换按钮的当前状态UF_MB_ask_toggle_state

    NX9+VS2012 1.打开D:\Program Files\Siemens\NX 9.0\UGII\menus\ug_main.men 找到装配和PMI,在中间加上一段 TOGGLE_BUTTON ...

  4. web开发者性能优化工具(一)

    web开发者性能优化工具 1   数据包嗅探器(在性能优化时,查看页面(包括页面中全部资源)的加载过程) HttpWatch (http://www.httpwatch.com/) 把网络流量用图形的 ...

  5. Python:获取当前py的文件名

    采用pathlib库 from pathlib import Path Path(__file__).name

  6. python+tushare获取A股所有股票代码和名称列表

    接口:stock_basic 描述:获取基础信息数据,包括股票代码.名称.上市日期.退市日期等 注:tushare模块下载和安装教程,请查阅我之前的文章 输入参数 名称      |      类型  ...

  7. Pathfinding 模板题 /// BFS oj21413

    题目大意: Description Bessie is stranded on a deserted arctic island and wants to determine all the path ...

  8. JavaScript学习总结(七)——ECMAScript6(ES6)

    一.ECMAScript概要 ECMAScript是一种由Ecma国际(前身为欧洲计算机制造商协会,英文名称是European Computer Manufacturers Association)通 ...

  9. .NET Core 3.0之深入源码理解Startup的注册及运行

    原文:.NET Core 3.0之深入源码理解Startup的注册及运行   写在前面 开发.NET Core应用,直接映入眼帘的就是Startup类和Program类,它们是.NET Core应用程 ...

  10. ECMAScript中所有参数传递的都是值,不可能通过引用传递参数

    今天在看JavaScript高级程序设计(第三版)时,看到了这个问题:ECMAScript中所有参数传递的都是值,不可能通过引用传递参数. 在我的印象中,其他语言比如Java,C++等,传递参数有两种 ...