欢迎关注我的微博:http://weibo.com/u/1659093193
比赛链接:http://www.acmore.net/contest.php?cid=1008
首先声明,我参加这场比赛纯属凑热闹,不过既然做了,就写一个解题报告,希望能帮助到需要帮助的同学。
这场比赛,总体来说难题适中(仅对我个人而言),对于初学者来说有点偏难,也有可能是我实力太弱了,呵呵,不过我说的是我自己真实感受。
下面奉上每一题的解题思路,希望能够给同学一点帮助。如果需要代码,可以私信我,这里就不贴代码了。如果读者有更好的解题方法,希望您不吝赐教,能够留言说说思路,在这里先谢过了。
Problem A 客户数量
这道题给出了将一个长度为n的糕点,切成单位长度。已知每次切割需要花费x*(n-x)时间,那么最后最短的时间是多少。当时猜了一个结论就是每次切一个单位下来,那么需要的时间就是(n-1)+(n-2)+----+1 = n*(n-1)/2。对于这个我不会证明,希望有读者可以给与帮助。
于是就相当于知道了每位客人来的时间和离开的时间为[a, b],然后求小Y在所有的顾客中,最多能服务的顾客数量。由于考虑到数据范围为10^5,而且时间范围为10^9,所以需要至少为nlogn时间复杂度的算法。
定义dp[i][j]表示前i个人中,服务j个人最短的结束服务时间,这里看起来是二维的,实际上在编程的时候只需要后面一维就可以了,因为遍历顾客本来就对应到了一层for循环。
于是我们简单写作dp[k]表示服务k个人,最小的结束时间。显然这个数组是具有单调不减性质的,因为服务人数越多,肯定服务结束时间越大。对于该状态定义,对于第i个顾客,二分查找到最大的j,使得dp[j]<=node[i].x(其中node[i].x表示第i个顾客到来的时间),用node[i].y尝试更新dp[j+1]。最后只需要遍历最大的j,使得dp[j]是可达的j就是最大的能服务的顾客的数量。
需要提醒一下的是,先对顾客数组进行排序,按照顾客结束服务时间从小到大排序,若是结束时间相同,则按照开始时间从小到大排序。于是最后总的复杂度是O(nlogn),可以通过。
Problem B 文本整齐度
这道题其实挺简单的,定义好了状态就是一道水题。
定义dp[i]表示以第i个单词为一行结束的最小整齐度,那么状态转移方程就是dp[i] = min(dp[j] + (m-used)^3) (其中 1<=j<=i)。
另外需要注意题目中说的是除了最后一行的整齐度的最小值,那么就是枚举word[k, n]可放入最后一行,取dp[k-1]的最小值就是最后的解了。建议计算过程使用long long。
Problem C 未覆盖定点数
这道题是首先有人过的,我也没多想,用线段树过的。seg[i]表示区间的和,只需要用线段树进行区间和的更新,最后查询就是seg[1]就是区间中1的个数,用n-seg[n]就是0的个数了。
这里需要注意在进行子区间赋值为1的时候,若我们发现整个区间的已经全是1了,那么我们显然不用继续往下更新了,直接返回即可。
其实我不认为这道题用线段树是最好的做法,若是其他人能有更好更简单的方法,希望能够分享讨论。
Problem D 1的数量
求区间[a, b]内的数所包含的1的个数,例如[111, 112]中1的个数为5,1<=a, b<=10^18,将最后的结果需要对10^9+7取模。
0, 1, 2, 3, ------, 9,
10, 11,12, 13, ----, 19,
20, 21, 22, 23, ------,29,
-- --- --
--- --- --
90, 91, 92, --------, 99,
100, 101, 102, ------, 109,
---
-----
990, 991, 992,--------, 999,
1000, 1001, 1002, -----------, 1009
对于这个问题,我们只要求[1, n]的区间内所有的数中包含1的个数,对此我们分情况讨论。
1在个位出现的情况:我们看到每隔10个数,个位出现一个1,因此总的个位1的个数为(n-1)/10 + 1;
1在十位出现的情况:我们看到十位出现1的情况是10, 11, -----, 19这样子重复出现,每100个出现一组这样的十位数,于是十位上1的个数为n/100*10+min(max((x%100-9), 0), 10)。前一部分表示有多少组这样的十位数,后一部分表示不满足完整一组的十位数上1的个数。
1在百位上出现的情况:百位上出现1的情况为100, 101, -----, 109,
110, 111, -----, 119,
----
190, 191, -------, 199.
于是我们知道每1000个数中会出现这样一组100个1,于是百位上出现1的个数为n/1000*100+min(max(n%1000-99, 0), 100)。其中前一部分表示完整的一组100个1,后面一部分表示不满足一组的百位上出现1的个数。
同理,1在其他位上出现的情况,依次类推即可。注意一点就是在求和的过程中对10^9+7取模。
Problem E 数字排列
这道题是说,给一个9位数,数中的相邻两数字之间会互相影响,两数的影响值已经给出来了,求重新排列数中的每个数字,不已前导零开头,使得所有数值的互相影响值最小。
一看到只有9位数,那么就进行全排列的枚举呗,也才9的阶乘,注意要排除前导零的情况,对每一个排列求一个影响值,取最小的影响值。
遍历全排列的写法就是每次拿当前的数字与后面的每一位交换进行dfs,知道了这个这道题就好写了。