重邮第八届ACM大赛-决赛题解报告
2017-04-23 18:49
239 查看
列表内容
长度为N的01序列一共有2N种,所以L的理论最大值为2N
当N比较小时,尝试暴力构造,找规律发现:
答案具有000…0……111…1的形式(N个0+中间部分+N个1)
尝试贪心构造:
初始化序列为11…100…0(N个1+N个0),并标记其中已经出现过的序列
尝试在末尾加0,若新组成的序列(当前序列的后N-1个字符+0)未出现,则确定加0,并标记该序列出现过。若出现过,则再尝试在末尾加1。
当序列无论加0加1都无法构成未出现过的序列时(长度达到理论上限时),停止
例如,N=3时
初始化序列为111000,vis表:000、100、110、111
尝试加0,新组成000,在vis表中
尝试加1,新组成001,不在vis表中
当前序列1110001,vis表:000、100、110、111、001
尝试加0,新组成010,不在vis表中
当前序列11100010,vis表:000、100、110、000、001、010
尝试加0,新组成100,在vis表中
尝试加1,新组成101,不在vis表中
当前序列111000101,vis表:000、100、110、000、001、010、101
此时可以发现,序列长度已经超过23=8,并且此时无论加0加1肯定也都无法组成新序列了。
当前序列长度为9?那是因为没有考虑到这是循环串。
事实上若去掉最后加的1,此时的序列为11100010,刚好满足条件,其最小表示为00010111
这个序列长度首先达到了理论最大值,并且由于贪心构造,字典序也得以保证。
用同样的构造方式,容易验证,对于n≤20,都可以得到长度L=2n的序列
长度为n的01串可以当成0∼2n−1的2进制数,可以用数组简单的实现vis表。
code
设切的位置为x,f(x)表示左边pizza的美味度,易知f(x)为单调函数
现在想求x1∈[0,n],使得f(x1)=f(n)2
使用二分法求x1即可
其中f(x),可以在O(n)内算出。只需要枚举每个圆与竖线的位置关系,在左边则全部加上,相交则求左部的面积。
code
不难想到,稳定排序的结果是唯一的
自己做一次稳定排序,导出p数组,然后再与给的p数组比较即可
code
设每个反应物、生成物前的系数为xi,根据质量守恒定律,对每一个元素建立一个线性方程,则得到了一个关于x的线性齐次方程组Ax=0。使用高斯消元解即可。
例如:
设x1H2+x2O2=x3H2O
则
{2x1−2x3=0(对H)2x2−x3=0(对O)
容易发现该方程组有一个自由变元,即有无穷组解。
但在所有系数的最大公因数为1的情形下,有唯一解。
解得
⎧⎩⎨⎪⎪x1=2x2=1x3=2
事实上,输入保证有唯一解,就说明,自由变元有且只有一个,而且其它变量都是这个变元的倍数。
根据这一点,使用完高斯消元后,将自由变元置为1,倒推出其他所有变量的值。此处需要使用分数类。最后通分,化所有系数为最简整数比。
code
设f[i][j]表示a1∼ai中乘积为j的非空子序列个数,则状态转移方程为:
f[i][j]=f[i−1][j]+∑ai|jf[i−1][jai]
边界条件为:
f[0][j]={1 (j=1)0 (j≠1)
第一维i只与i-1有关,所以可以滚动优化掉
第二维j虽然大,但是有效状态只有k的因子,是k√ 级别的,可以预处理出k的因子然后离散化,也可以直接用map
code
先考虑:如果确定行数后,可以check可行性吗?
当然是可以的。假定行数为row,那么第一列占用max{a1∼arow},第二列占用max{arow+1∼a2∗row}…最后再考虑列间空格,就可以算出占用的最大宽度。
check一次row的可行性可以轻松做到O(n)的复杂度。
于是我们想到二分row
蓝儿。。蓝儿。。WA了
考虑这组数据:
15 14
3 3 3 3 3 4 4 4 4 4 5 5 5 5 5
二分做法的流程为:
l = 1, r = 15, mid = (1+15)/2 = 8
check(8):
3 4
3 4
3 5
3 5
3 5
4 5
4 5
4
宽度为4 + 5+ 1 = 10 < 14
于是l = 1, r = 7, mid = (1+7)/2 = 4
check(4):
3 3 4 5
3 4 4 5
3 4 5 5
3 4 5
宽度为3 + 4 + 5 + 5 + 3 = 20 > 14
于是l = 5 , r = 7, mid = (5+7)/2 = 6
check(6):
3 4 5
3 4 5
3 4 5
3 4
3 5
4 5
宽度为4 + 5 + 5 + 2 = 16 > 14
于是l = 7, r = 7, mid = 7
check(7):当然也不行
最终得到答案8
然而容易发现答案是5
说明,这个题目并不满足二分的条件——单调性,即并不是说只要row = i可行,那row>i就都可行
所以正确的做法是,check每一种row的值(1~n)
当然此时就无法使用O(n)的RMQ方法了
考虑使用线段树或者Sparse-Table算法
可以计算出,使用上述方法需要的RMQ次数为:
O(n1+n2+...+nn)=O(nlogn)
若使用ST算法,则O(nlogn)预处理后,O(1)回答RMQ,总时间复杂度O(nlogn),空间复杂度O(nlogn)
若使用线段树,O(n)预处理后,O(logn)回答RMQ,总时间复杂度O(nlog2n),空间复杂度O(n)
这里丧病了一波,n=2∗106,同时卡了线段树(TLE)和普通的ST(MLE)
回忆ST算法,f[i][j]表示min{aj∼aj+2i−1},f[i][j]=min{f[i−1][j],f[i−1][j+2i−1}
可以发现i只与i-1有关,所以可以滚动。
当前这一轮i可以回答满足2i≤r−l+1≤2i+1的RMQ(l,r)
所以做法就出来了。从小到大枚举row,若当前这一轮ST无法满足查询需要(即row>2i+1),则递推下一轮ST。这样就把空间复杂度优化为O(n)了
code
当然这里zkw线段树+一点简单的优化也可以过(owj)
递归生成所有方案
最后判断时注意浮点误差
code
简单的画一个图可以发现,可以到达的点是很有规律的。
设左下角坐标为(0,0),则每次跳后,横纵坐标之和增加3。所以能够到达的点的横纵坐标之和一定是3的倍数。
容易发现,这事实上就是一个杨辉三角。横纵坐标之和反应了该点所在的行,横纵坐标之差反应了这是该行的第几个。且满足三角形递推式Cmn=Cm−1n−1+Cmn−1
接下来的任务变成了求组合数,初赛中已经介绍过了。
code
编码方式显然是哈夫曼编码
一共有4n种字符串,n=20时,420=1099511627776≈1012
但实际上,对于ABCD四种字符个数都相等的字符串,他们出现的概率是一样的,所以在合并的时候可以批量合并。可以用优先队列维护二元组(p,cnt),在合并的时候:
若top的cnt>1,则将偶数部分批量合并 (p∗2,cnt2),若有单个的,再重新入队(p,1)
若top的cnt=1,则再取p第二小的出来合并,入队(p1+p2,1)和(p2,cnt2−1)
三重循环枚举A、B、C的数量(D的数量为n-A-B-C),利用乘法原理和除法原理,可以预处理出所有的(p,cnt)二元组。可以发现,当n=20时,二元组的数量只有1771个,时间复杂度完全可以接受
期望编码长度在合并的过程中可以顺便计算
code
A. 果姐姐的项链
贪心、构造长度为N的01序列一共有2N种,所以L的理论最大值为2N
当N比较小时,尝试暴力构造,找规律发现:
答案具有000…0……111…1的形式(N个0+中间部分+N个1)
尝试贪心构造:
初始化序列为11…100…0(N个1+N个0),并标记其中已经出现过的序列
尝试在末尾加0,若新组成的序列(当前序列的后N-1个字符+0)未出现,则确定加0,并标记该序列出现过。若出现过,则再尝试在末尾加1。
当序列无论加0加1都无法构成未出现过的序列时(长度达到理论上限时),停止
例如,N=3时
初始化序列为111000,vis表:000、100、110、111
尝试加0,新组成000,在vis表中
尝试加1,新组成001,不在vis表中
当前序列1110001,vis表:000、100、110、111、001
尝试加0,新组成010,不在vis表中
当前序列11100010,vis表:000、100、110、000、001、010
尝试加0,新组成100,在vis表中
尝试加1,新组成101,不在vis表中
当前序列111000101,vis表:000、100、110、000、001、010、101
此时可以发现,序列长度已经超过23=8,并且此时无论加0加1肯定也都无法组成新序列了。
当前序列长度为9?那是因为没有考虑到这是循环串。
事实上若去掉最后加的1,此时的序列为11100010,刚好满足条件,其最小表示为00010111
这个序列长度首先达到了理论最大值,并且由于贪心构造,字典序也得以保证。
用同样的构造方式,容易验证,对于n≤20,都可以得到长度L=2n的序列
长度为n的01串可以当成0∼2n−1的2进制数,可以用数组简单的实现vis表。
code
B. 切披萨
二分设切的位置为x,f(x)表示左边pizza的美味度,易知f(x)为单调函数
现在想求x1∈[0,n],使得f(x1)=f(n)2
使用二分法求x1即可
其中f(x),可以在O(n)内算出。只需要枚举每个圆与竖线的位置关系,在左边则全部加上,相交则求左部的面积。
code
C. 稳定排序
签到题不难想到,稳定排序的结果是唯一的
自己做一次稳定排序,导出p数组,然后再与给的p数组比较即可
code
D. 方程式配平
高斯消元+分数类设每个反应物、生成物前的系数为xi,根据质量守恒定律,对每一个元素建立一个线性方程,则得到了一个关于x的线性齐次方程组Ax=0。使用高斯消元解即可。
例如:
设x1H2+x2O2=x3H2O
则
{2x1−2x3=0(对H)2x2−x3=0(对O)
容易发现该方程组有一个自由变元,即有无穷组解。
但在所有系数的最大公因数为1的情形下,有唯一解。
解得
⎧⎩⎨⎪⎪x1=2x2=1x3=2
事实上,输入保证有唯一解,就说明,自由变元有且只有一个,而且其它变量都是这个变元的倍数。
根据这一点,使用完高斯消元后,将自由变元置为1,倒推出其他所有变量的值。此处需要使用分数类。最后通分,化所有系数为最简整数比。
code
E. The product is k
动态规划设f[i][j]表示a1∼ai中乘积为j的非空子序列个数,则状态转移方程为:
f[i][j]=f[i−1][j]+∑ai|jf[i−1][jai]
边界条件为:
f[0][j]={1 (j=1)0 (j≠1)
第一维i只与i-1有关,所以可以滚动优化掉
第二维j虽然大,但是有效状态只有k的因子,是k√ 级别的,可以预处理出k的因子然后离散化,也可以直接用map
code
F. js的LED屏幕
RMQ先考虑:如果确定行数后,可以check可行性吗?
当然是可以的。假定行数为row,那么第一列占用max{a1∼arow},第二列占用max{arow+1∼a2∗row}…最后再考虑列间空格,就可以算出占用的最大宽度。
check一次row的可行性可以轻松做到O(n)的复杂度。
于是我们想到二分row
蓝儿。。蓝儿。。WA了
考虑这组数据:
15 14
3 3 3 3 3 4 4 4 4 4 5 5 5 5 5
二分做法的流程为:
l = 1, r = 15, mid = (1+15)/2 = 8
check(8):
3 4
3 4
3 5
3 5
3 5
4 5
4 5
4
宽度为4 + 5+ 1 = 10 < 14
于是l = 1, r = 7, mid = (1+7)/2 = 4
check(4):
3 3 4 5
3 4 4 5
3 4 5 5
3 4 5
宽度为3 + 4 + 5 + 5 + 3 = 20 > 14
于是l = 5 , r = 7, mid = (5+7)/2 = 6
check(6):
3 4 5
3 4 5
3 4 5
3 4
3 5
4 5
宽度为4 + 5 + 5 + 2 = 16 > 14
于是l = 7, r = 7, mid = 7
check(7):当然也不行
最终得到答案8
然而容易发现答案是5
说明,这个题目并不满足二分的条件——单调性,即并不是说只要row = i可行,那row>i就都可行
所以正确的做法是,check每一种row的值(1~n)
当然此时就无法使用O(n)的RMQ方法了
考虑使用线段树或者Sparse-Table算法
可以计算出,使用上述方法需要的RMQ次数为:
O(n1+n2+...+nn)=O(nlogn)
若使用ST算法,则O(nlogn)预处理后,O(1)回答RMQ,总时间复杂度O(nlogn),空间复杂度O(nlogn)
若使用线段树,O(n)预处理后,O(logn)回答RMQ,总时间复杂度O(nlog2n),空间复杂度O(n)
这里丧病了一波,n=2∗106,同时卡了线段树(TLE)和普通的ST(MLE)
回忆ST算法,f[i][j]表示min{aj∼aj+2i−1},f[i][j]=min{f[i−1][j],f[i−1][j+2i−1}
可以发现i只与i-1有关,所以可以滚动。
当前这一轮i可以回答满足2i≤r−l+1≤2i+1的RMQ(l,r)
所以做法就出来了。从小到大枚举row,若当前这一轮ST无法满足查询需要(即row>2i+1),则递推下一轮ST。这样就把空间复杂度优化为O(n)了
code
当然这里zkw线段树+一点简单的优化也可以过(owj)
G. The 24 Game
搜索递归生成所有方案
最后判断时注意浮点误差
code
H. 马
数学简单的画一个图可以发现,可以到达的点是很有规律的。
设左下角坐标为(0,0),则每次跳后,横纵坐标之和增加3。所以能够到达的点的横纵坐标之和一定是3的倍数。
容易发现,这事实上就是一个杨辉三角。横纵坐标之和反应了该点所在的行,横纵坐标之差反应了这是该行的第几个。且满足三角形递推式Cmn=Cm−1n−1+Cmn−1
接下来的任务变成了求组合数,初赛中已经介绍过了。
code
I. 魔王剑术
哈夫曼编码编码方式显然是哈夫曼编码
一共有4n种字符串,n=20时,420=1099511627776≈1012
但实际上,对于ABCD四种字符个数都相等的字符串,他们出现的概率是一样的,所以在合并的时候可以批量合并。可以用优先队列维护二元组(p,cnt),在合并的时候:
若top的cnt>1,则将偶数部分批量合并 (p∗2,cnt2),若有单个的,再重新入队(p,1)
若top的cnt=1,则再取p第二小的出来合并,入队(p1+p2,1)和(p2,cnt2−1)
三重循环枚举A、B、C的数量(D的数量为n-A-B-C),利用乘法原理和除法原理,可以预处理出所有的(p,cnt)二元组。可以发现,当n=20时,二元组的数量只有1771个,时间复杂度完全可以接受
期望编码长度在合并的过程中可以顺便计算
code
相关文章推荐
- 重邮第八届ACM大赛-预赛题解报告
- “Wishare杯”南邮第八届大学生程序设计竞赛之现场决赛 题解报告
- pongo(csdn英雄会题解)之三元组的数量--英雄会第二届在线编程大赛·CSDN现场决赛
- 哈理工软件学院"兆方美迪"杯第六届程序设计大赛【高年级组】--决赛(离官方最近的题解)
- 第八届河南省acm大赛。。。
- 第八届北航程序设计大赛网络预赛解题报告
- ACM题解报告——HD1496
- nyoj 1236挑战密室 河南省第八届大学生程序设计大赛acm
- ACM题解报告——HD1022
- SDUT 3896 HEX 山东第八届ACM大赛D题(组合数学)
- (2017)第八届蓝桥杯大赛个人赛省赛(软件类) C/C++ 大学A组 题解(第九题)
- 第八届蓝桥杯大赛个人赛省赛C++ B组 题解+原题 (填空题)
- 【题解】英雄会第二届在线编程大赛·CSDN现场决赛:三元组的数量
- 2015浙江财经大学ACM有奖周赛(一) 题解报告
- 河南理工大学程序设计(ACM)大赛解题报告
- ACM题解报告——HD1006
- 2017中北大学程序设计大赛决赛题解
- SDUT 3895 fireworks 山东第八届ACM大赛C题(组合数学(杨辉三角)+逆元)
- 南京理工大学第八届程序设计大赛(校外镜像)题解报告
- (2017)第八届蓝桥杯大赛个人赛省赛(软件类) C/C++ 大学A组 题解(第三题和第四题)