【题解】清北学堂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