【NOI2014】随机数生成器

【NOI2014】随机数生成器

【题目描述】

小H最近在研究随机算法。随机算法往往需要通过调用随机数生成函数(例如Pascal中的random和C/C++中的rand)来获得随机性。事实上,随机数生成函数也并不是真正的“随机”,其一般都是利用某个算法计算得来的。比如,下面这个二次多项式递推算法就是一个常用算法:算法选定非负整数 x0,a,b,c,d 作为随机种子,并采用如下递推公式进行计算:

xi=(a*xi-1^2+b*xi-1+c)mod d

对于任意 i≥1,这样可以得到一个任意长度的非负整数数列{xi }(i≥1),一般来说,我们认为这个数列是随机的。利用随机序列{xi }(i≥1),我们还可以采用如下算法来产生一个1到K的随机排列{Ti }(i=1)K:初始设T为1到K的递增序列;对T进行K次交换,第 i 次交换,交换 Ti 和 T((x(i) mod i)+1) 的值。此外,小H在这 K 次交换的基础上,又额外进行了 Q 次交换操作,对于第 i 次额外交换,小H会选定两个下标 ui 和 vi,并交换 T(u_i ) 和 T(v_i ) 的值。为了检验这个随机排列生成算法的实用性,小H设计了如下问题:小H有一个 N 行 M 列的棋盘,她首先按照上述过程,通过 N×M+Q 次交换操作,生成了一个 1~N×M 的随机排列 {Ti }(i=1)(N×M),然后将这 N×M 个数逐行逐列依次填入这个棋盘:也就是第 i 行第 j 列的格子上所填入的数应为 T((i-1)*M+j)。接着小H希望从棋盘的左上角,也就是第一行第一列的格子出发,每次向右走或者向下走,在不走出棋盘的前提下,走到棋盘的右下角,也就是第 N 行第 M 列的格子。小H把所经过格子上的数字都记录了下来,并从小到大排序,这样,对于任何一条合法的移动路径,小H都可以得到一个长度为 N+M-1 的升序序列,我们称之为路径序列。小H想知道,她可能得到的字典序最小的路径序列应该是怎样的呢?

【输入】

输入的第1行包含5个整数,依次为 x_0,a,b,c,d ,描述小H采用的随机数生成算法所需的随机种子。 第2行包含三个整数 N,M,Q ,表示小H希望生成一个1到 N×M 的排列来填入她 N 行 M 列的棋盘,并且小H在初始的 N×M 次交换操作后,又进行了 Q 次额外的交换操作。 接下来 Q 行,第 i 行包含两个整数 u_i,v_i,表示第 i 次额外交换操作将交换 T_(u_i )和 T_(v_i ) 的值。

【输出】

输出一行,包含 N+M-1 个由空格隔开的正整数,表示可以得到的字典序最小的路径序列。

【输入样例】

1 3 5 1 71 
3 4 3 
1 7 
9 9 
4 9

【输出样例】

1 2 6 8 9 12

【数据范围】

2<=n,m<=5000

0<=q<=50000

0<=a<=300

0<=b,c<=10^8

0<=x0<d<=10^8

1<=vi,ui<=n*m

(只复制来了最大的数据范围)

【题解】

┭┮﹏┭┮先是MLE,然后是TLE,最后还来了PE……

(以上属于吐槽部分OTL)

解法相当暴力简洁0.0,首先暴力构造好T数组(是滴就是暴力构造),为了省空间不用转矩阵了,用的时候算一算每一个数对应的位置就好。

再用一个数组P,P[i]表示i在T数组中的位置,以便接下来操作。

重头戏就是接下来的贪心了0.0要求排序后字典序最小,那肯定贪心先取1,如果可以的话再取2,然后再考虑3……依此类推。当我取了1以后,找出1在矩阵中的位置,那么这个位置的左下角和右上角肯定不用了,用一个bool数组标记一下(开int数组就会MLE……)。显然这个贪心策略是正确的,因为能取到x时,排序后比x大的数价值都低于x,所以依次取下去一定能得到最优的序列,而且这个序列一定是一条路径(这个不太好证明0.0我是手画了几个,然后跟着感觉走……)

在标记时,如果暴力枚举会让复杂度达到O(nm*(n+m)),导致TLE,所以采用两个bfs,一个向左下,另一个向右上,bfs遇到已被标记过的点就不加入队列了,因为这个点既然被标记过,说明曾被加入队列,那这个点左下方或右上方也一定全部遍历过了。使用bfs,每个数最多被标记到一次,复杂度降低为O(nm),等于暴力构造的复杂度,所以总复杂度也就只有O(nm),但似乎常数灰常大O.o

最后提醒下,BZOJ目测全文比对,小心PE(当然以后可能会改吧)。

特别感谢【绿色的云】的讲解,给我提供了基本的思路。

【代码】

各种苦逼,果然我离NOI还有距离OTL

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值