【题解】清北学堂DP营考试

清北学堂DP营考试

共4题,全部为DP题,AC第一题,第二题60,第三题骗到10,第4题骗到20

T1签到题

【问题描述】

你是能看到第一题的 friends呢。
——hja

众所周知,小葱同学擅长计算,尤其擅长计算组合数,但这个题和组合数没
什么关系。
给定𝑁个数a1, a2,⋯, a𝑁,找到一个区间a𝑙 , a𝑙+1,⋯, a𝑟使得a𝑙 + a𝑙+1 + ⋯+ a𝑟
最大。

【输入格式】

第一行一个整数代表𝑁。
第二行𝑁个整数代表a1, a2,⋯, a𝑁。

【输出格式】

一行一个数代表答案。

【样例输入】

3
1 -1 1

【样例输出】

1

【数据规模与约定】

对于40%的数据,𝑁 ≤ 100。
对于60%的数据,𝑁 ≤ 1000。
对于另外20%的数据,ai ≥ 0。
对于100%的数据,1 ≤ 𝑁 ≤ 105, |ai| ≤ 103。

T2练习题

【问题描述】

你是能看到第二题的 friends呢。
——aoao
众所周知,小葱同学擅长计算,尤其擅长计算组合数,但这个题和组合数没
什么关系。
𝑁个数排成一个环,要求从中选出𝐾个数,记为a1, a2,⋯, a𝐾。你的目标是最
小化|a1 − a2| + |a2 − a3| +⋯+ |a𝐾−1 − a𝐾| + |a𝐾 − a1|并且使得选出的𝐾个数
互不相邻。

【输入格式】

第一行两个整数𝑁,𝐾。
第二行𝑁个整数代表环上的数。

【输出格式】

一行一个数代表答案。

【样例输入】

5 2
1 2 3 4 5

【样例输出】

4

【数据规模与约定】

对于40%的数据,𝑛 ≤ 10。
对于60%的数据,𝑛 ≤ 20。
对于100%的数据,1 ≤ 2𝐾 ≤ 𝑁 ≤ 100,所有数都不超过106。

状态

f[i ] [j ] [r ]选到第i个数,选了j个数了,第一个数选的是第r个数(没错我也是这么想的)

转移

枚举上一个数t

f[i] [j + 1] [r] = max{f[t] [j] [r] + abs(a[t] - a[i])};

CaO

这个题n^4是可以过的,但是我才60,zhx:"写错了呗"

T3骗分题

【问题描述】

你是能看到第三题的 friends呢。
——laekov
众所周知,小葱同学擅长计算,尤其擅长计算组合数,但这个题和组合数没
什么关系。
有𝑁个人,每个人都有两个属性值ai,bi。你可以任意的交换任意两个人的任
意一个属性(如ai和bj)交换,使得所有人的两个属性值之差的绝对值小于等于
c。问最小所需要的交换次数。

【输入格式】

第一行两个整数𝑁, c。
接下来每行两个整数代表属性值。

【输出格式】

一行一个整数代表答案。如果答案不存在则输出−1。

【样例输入】

3 0
3 3
2 3
2 3

【样例输出】

1

【数据规模与约定】

对于20%的数据,𝑁 ≤ 3。
对于40%的数据,𝑁 ≤ 8。
对于另外20%的数据,c = 0。
对于另外20%的数据,c = 1。
对于100%的数据,1 ≤ 𝑁 ≤ 16, c ≤ 106且属性值也不超过106。

复杂度

n <= 16说明是3 ^ n 的做法,所以状压(好像讲状压时我写语文来着)

状态1(正常人除了我这样的菜鸡应该会这样设计状态但是这是不对的)

f[i],i是一个n位二进制数,表示使得i所对应的集合里所有人都合法的最少交换次数。所谓i所对应的集合,是指这一位是1的人所组成的集合。交换只能在集合内部进行。

QAQ这个玩意没法转移

状态2(这是对的!)

如果有解,答案的上限是n - 1。

判断有无解:把所有的属性值拎出来,共2 * n个,从小到大排序,最优(使每一组两个数之差最小)的组合方案是相邻的两个数两两结合。然后依次判断,如果有某一组不满足两数绝对值之差小于等于c,那么就没有解。cout << -1;

交换:

如果说分成两部分,左边m人,右边n - m人

如果左边内部可以通过内部交换合法,左边要操作m - 1次,右边内部也可以通过内部交换合法,要用n - m - 1次,那么左右合并,共n - 2次操作

如果能分成3组,总操作就是n-3次

分成4组就更好了,越多越好

状态来了:

就像状压DP一直做的那样,用数i表示一个集合,某一位是1,表明这个人在集合内

f[i]表示集合里的人最多能分成几组,满足每组内部可以自行交换合法

转移

f[i] = max(f[s]+f[i - s])

最后的答案:n - f[2 ^ n - 1]

初始化

就是相邻的两个数b和b+1也就是一组,如果满足差的绝对值小于等于c,f[i] = 1

技巧

先确定答案的上界,反推出这个上界带来的性质

T4是个啥

【问题描述】

你是能看到第四题的 friends呢。
——rivenhe
众所周知,小葱同学擅长计算,尤其擅长计算组合数,但这个题和组合数没
什么关系。
给出𝑁个三元组,第𝑖个三元组的数为(ai , bi , ci)。 你可以按照任意的顺序排列
这些三元组,但是你需要保证排列之后两个相邻三元组中对应的数,都满足靠前
三元组小于等于靠后三元组的数,即\(a_i ≤ a_{i+1}, b_i ≤ b_{i+1}, c_i ≤ c_{i+1}\)。但是直接给出
的𝑁个三元组可能不能达到要求,所以你可以对每个数进行增加操作。给一个数
增加𝑥的代价是𝑥。现在问最少需要多少的代价能够完成题目给定的要求。

【输入格式】

一行一个数代表𝑁。
接下来𝑁行,每行三个整数代表一个三元组。

【输出格式】

一行一个数代表答案,注意可能爆 int。

【样例输入】

3
1 1 5
6 3 4
2 5 3

【样例输出】

5

【样例解释】

给第二个三元组第二个数加2第三个数加1,给第三个三元组第三个数加2,
再按照1,3,2的顺序排列三元组我们可以得到(1,1,5), (2,5,5), (6,5,5)。

【数据规模与约定】

对于40%的数据,𝑛 ≤ 5。
对于另外20%的数据,ai = bi = ci。
对于90%的数据,𝑛 ≤ 50。
对于100%的数据,1 ≤ 𝑛 ≤ 250,0 ≤ ai , bi , ci ≤ 10^9。

暴力有40分,枚举所有排列

90分做法

max_a = max{a1, a2...an}

最优解里面所有a的值最大为max_a

分别给a,b,c从小到大排序,得到:

a'_1,a'_2...a'_n

b'_1,b'_2,...b'_n

c'_1,c'_2,...c'_n

状态

f[i] [j] [k] 表示已经选最多的三元组,[旧状态:选了若干个三元组(不知道几个),无法确定某个三元组是否已选]这些三元组里面a最大为a‘_i,b最大为b’_j,c最大为c'_k的时候,所需的最小代价

选了一组:

什么样的三元组没被选过:

(a_r, b_r, c_r)满足a_r > a'_i或b_r > b'_j或c_r > c'_k

如果a_r <= a_i'&& b_r <= b_j' && c_r <= c_k',那这个三元组一定已选[如果是旧状态:只能说明有可能已选]

答案

f[n] [n] [n]

转移

就是不断地选呗

枚举1 <= r <= n,没选就选上,a_r > a'_i或b_r > b'_j或c_r > c'_k的就是没选过的

f[i] [j] [k] ->f[max(i,x)] [max(j, y)] [max(k, t)] 其中a_r = a'_x, b_r = b'_y, c_r = c'_t(就是找到这个a_r从小到大排第x)

设为f[x'] [y'] [t']

我们选上了第r个三元组,但是不仅仅选了它一个,所有转移后满足现在的条件的三元组都加入了

因为我们的定义是下一个加入的是第r个,所以其余的新加入的成员都要接在第r个后面

加入之后,这些所有的三元组必须变成(a'(x'), b'(y'), c'(t')),新增的代价就是m*(a'(x') - a'i) + m*(b'(y') - b'j) + m *(c'(t') - c'_k)

其中m是新加入的三元组的个数

前缀和O(1)转移

复杂度

O(n^4)

100分做法(n^3)

同样的状态

转移

一个数一个数地加,一个三元组分3次加,根据添加顺序得到一个3 *n 的排列

只有三个数都被加入的三元组才算被加进去,我们要看看一个三元组的最后一个数是何时被加入的

//伦无语次

算了放弃这个正解,明年再看吧

最后

论zhx取名的深意

super Mario maker two

posted @ 2020-04-05 20:59  _Buffett  阅读(457)  评论(0编辑  收藏  举报