T1. 定义F(x)=各位数字的阶乘之积,给定a<=1e30,求最大的不包含0/1的x使得F(x)=F(a)。
题解:沙茶题。每一位数字分开考虑然后打表即可。
T2. 给一个n*m的字符矩阵(n,m<=2000),求最少删除多少列使得每一行的字符串单调不减。
题解:沙茶题,保存当前这一行是否和上一行相等;如果相等并且上一和的这一列的字符大就删除,否则更新这个数组。
复杂度O(nm)。
T3. 给一列n个数。每次可以把相邻两个相同的数合并成这个数值+1.
请操作若干次使得剩余数列数字的最大值最大。
50%:N<=100.
95%:N<=100000
100%:N<=2000000.数列中的数字<=40.
注:最后5%的数据时限0.5秒。
题解:
首先考场上非常迅速的就能想到50%的做法。
就是设dp[i][j]表示[i,j]这一段能否合并成一个数字。显然如果可以,那么这个数字是确定的。
不能就是 -1.
转移就是枚举断点i<=k<j,看[i,k]和[k+1,j]合并成的数字是否相等,如果相等dp[i][j]=max{dp[i][k]+1}。
然后所有dp取个max即可。
然后过了一会注意到最后即使把所有数字合并起来数字也不会特别大所以可以放到状态里面,即:
设dp[i][j]表示末尾为i的某一段数字,能否合并为j。其中j是O(logn+a[i])级别的。
然后发现这样不能转移,因为不知道以i为末尾的数列合并成j-1时候左端点在哪里。
因此用dp[i][j]表示合并成j的时候的左端点,这样dp[i][j]=dp[dp[i][j-1]-1][j-1]。
如果做不到就是0.
然后if(dp[i][j]) ans=max(ans,j)。
这样ans就是答案。这样可以得到95分。
感觉这种本质上是交换状态。
不知道“绝大多数状态没有用”是怎么观察出来的。
然后事实上我们可以先枚举j,然后可以把空间优化到O(n);
这样常数就比较小,然后场上有两个人跑了0.500秒卡过。
这我居然没有注意到!!!!我真是沙茶了。
还有sjk大佬贪心了95分?%%%
数据不够强,但是正确性在随机情况下非常优秀。
关于造数据:先随机扔几个数字,然后开始往外拆,随机决定是否要往下拆。
这样很容易被某些算法hack掉。
事实上正解是这么搞的:
可能是用什么栈或者队列乱搞?
搞一个单调栈即可。
std2里面有注释。大意就是左边不能和右边搞起来就把左边搞一下然后扔掉。
曹震dalao也写了个正解,但是貌似更复杂但是好像更通用的多?