(非本校)湖南工业大学个人选拔赛第一场 解题报告

比赛链接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,知道了这个这道题就好写了。


至http://blog.csdn.net/geniusluzh/article/details/8793716

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值