Educational Codeforces Round 69 D E
Educational Codeforces Round 69 题解
题目编号 | A | B | C | D | E | F |
---|---|---|---|---|---|---|
完成情况 | √ | √ | √ | ★ | ★ | - |
D. Yet Another Subarray Problem
一个子数组的价值为:
\]
求解其最大值。子数组可以为空,此时价值为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\)的余数就可以了。
\]
\]
\]
\]
一定要留心\(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\)降序排序
\(dp[0][i]\)表示前i个套娃,第\(i\)个套娃在最里面的最小额外值
\(dp[1][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
一个子数组的价值为:
\]
求解其最大值。子数组可以为空,此时价值为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\)中有很多不合题意的量,我们不能用这些量去进行转移,于是初始全部赋值为\(-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的更多相关文章
- Educational Codeforces Round 69 (Rated for Div. 2) E. Culture Code
Educational Codeforces Round 69 (Rated for Div. 2) E. Culture Code 题目链接 题意: 给出\(n\)个俄罗斯套娃,每个套娃都有一个\( ...
- Educational Codeforces Round 69 D. Yet Another Subarray Problem
Educational Codeforces Round 69 (Rated for Div. 2) D. Yet Another Subarray Problem 题目链接 题意: 求\(\sum_ ...
- Educational Codeforces Round 69 (Rated for Div. 2)
A. DIY ...
- 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 \( ...
- Educational Codeforces Round 69 (Rated for Div. 2) C. Array Splitting 水题
C. Array Splitting You are given a sorted array
- Educational Codeforces Round 69
目录 Contest Info Solutions A. DIY Wooden Ladder B. Pillars C. Array Splitting D. Yet Another Subarray ...
- Educational Codeforces Round 69 (Rated for Div. 2) A~D Sloution
A. DIY Wooden Ladder 题意:有一些不能切的木板,每个都有一个长度,要做一个梯子,求梯子的最大台阶数 做梯子的木板分为两种,两边的两条木板和中间的若干条台阶木板 台阶数为 $k$ 的 ...
- Educational Codeforces Round 69 E - Culture Code (最短路计数+线段树优化建图)
题意:有n个空心物品,每个物品有外部体积outi和内部体积ini,如果ini>outj,那么j就可以套在i里面.现在我们要选出n个物品的一个子集,这个子集内的k个物品全部套在一起,且剩下的物品都 ...
- 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[ ...
随机推荐
- NX二次开发-获取工程图尺寸的值UF_DRF_ask_dim_info
UF_initialize(); //遍历所有尺寸 ; tag_t DimTag = NULL_TAG; UF_OBJ_cycle_objs_in_part1(UF_PART_ask_display_ ...
- NX二次开发-打开文件夹,并同时选中指定文件
NX9+VS2012 #include <uf.h> #include <uf_ui.h> #include <uf_part.h> #include <at ...
- C++ string的大小写转换【转载】
转载自https://www.cnblogs.com/balingybj/p/4678850.html 将一个string转换成大写或者小写,是项目中经常需要做的事情,但string类里并 没有提供这 ...
- 6.RabbitMQ Linux安装
RabbitMQ在Linux上安装,需要很多依赖库,如何不能解决依赖库德版本问题,可能会比较麻烦,最好结合Yum进行安装,我这里使用的Linux环境是64位CentOS6.2 ,使用Yum源是阿里云的 ...
- 转: div:给div加滚动条 div的滚动条设置
div 的滚动条问题: 两种方法: 一. <div style=" overflow:scroll; width:400px; height:400px;”></div&g ...
- SpringBoot-集成PageHelper5.1.2踩坑
背景就不介绍了,项目是SpringBoot+MyBatis搭建的,需要集成git上的PageHelper5.1.2,这个插件大家都比较熟悉了 之前一直用的PageHelper4.0.3,集成是这样的: ...
- 《转》python
转自http://www.cnblogs.com/BeginMan/archive/2013/06/03/3114974.html 1.print语句调用str()函数显示,交互式解释器调用repr( ...
- sys_call_table HOOK
sys_call_table 这个东西,其实和 Windows 下的 SSDT 表,在功能上完全相同. 前一阵子学Linux驱动,遇到了这个系统调用表,然后我就想到Windows的SSDT表,既然SS ...
- Ansible的copy模块批量下发文件
copy模块的参数,ansible 主机组 -m copy -a '' src: 指定源文件或目录 dest: 指定目标服务器的文件或目录 backup: 是否要备份 owner: 拷贝到目标服务器后 ...
- struts2类型转换2
如何自定义类型转换器 ? 1). 为什么需要自定义的类型转换器 ? 因为 Struts 不能自动完成 字符串 到 引用类型 的 转换. 2). 如何定义类型转换器: I. 开发类型转换器的类: 扩展 ...