[NOI2014]随机数生成器 题解
原题网址:
bzoj P3671
洛谷 P2354
附原题:
时间限制 | 内存限制 |
---|---|
1.00s ~ 5.00s | 250.00MB |
题目描述
小 H 最近在研究随机算法。随机算法往往需要通过调用随机数生成函数(例如 Pascal 中的 random 和 C/C++中的 rand)来获得随机性。事实上,随机数生成函数也并不是真正的“随机”,其一般都是利用某个算法计算得来的。
比如,下面这个二次多项式递推算法就是一个常用算法:
算法选定非负整数作为随机种子,并采用如下递推公式进行计算。
对于任意 $x_i==(a×x+b×x_{i-1}^2+c) mod 这样可以得到一个任意长度的非负整数数列 ,一般来说,我们认为这个数列是随机的。
利用随机序列,我们还可以采用如下算法来产生一个到 的随机排列
1、初始设为到的递增序列;
2、对进行次交换,第次交换,交换和mod
此外,小 H 在这次交换的基础上,又额外进行了次交换操作,对于第i 次额外交换,小 H 会选定两个下标,并交换的值
为了检验这个随机排列生成算法的实用性,小 H 设计了如下问题:
小 H 有一个 N 行 M 列的棋盘,她首先按照上述过程,通过次交换操作,生成了一个的随机排列,。然后将这个数逐行逐列依次填入这个棋盘:也就是第行第列的格子上所填入的数应为。
接着小 H 希望从棋盘的左上角,也就是第一行第一列的格子出发,每次向右走或者向下走,在不走出棋盘的前提下,走到棋盘的右下角,也就是第 行第列的格子。
小 H 把所经过格子上的数字都记录了下来,并从小到大排序,这样,对于任何一条合法的移动路径,小 H 都可以得到一个长度为的升序序列,我们称之为路径序列。
小 H 想知道,她可能得到的字典序最小的路径序列应该是怎样的呢?
输入格式
第1行包含5个整数,依次为描述小H采用的随机数生成算法所需的随机种子。
第2行包含三个整数表示小H希望生成一个1到 的排列来填入她行列的棋盘,并且小H在初始的次交换操作后,又进行了次额外的交换操作。
接下来行,第行包含两个整数,表示第次额外交换操作将交换的值。
输出格式
输出一行,包含个由空格隔开的正整数,表示可以得到的字典序最小的路径序列。
输入输出样例
输入
1 3 5 1 71
3 4 3
1 7
9 9
4 9
输出
1 2 6 8 9 12
数据范围
题解内容
终于把题目写完了,markdown写了半个多小时
前面blablabla讲了一大堆废话
一句话讲,就是教你怎么生成一个随机函数,代码直接按照它的做法写下来,注意数据范围,要加不然会直接RE就像我一样:
炸了,所以加上强制转换,就可以了~~~~~~
scanf("%d%d%d%d%d",&x[0],&a,&b,&c,&d); scanf("%d%d%d",&n,&m,&q); int s=n*m; int i,j,tmp,tmps; for(i=1;i<=s+1;i++) x[i]=((long long)a*x[i-1]*x[i-1]+(long long)b*x[i-1]+c)%d; for(i=1;i<=s;i++) t[i]=i;//注意这里的(longlong),不加会炸掉的 for(i=1;i<=s;i++){ tmps=x[i]%i+1; tmp=t[i]; t[i]=t[tmps]; t[tmps]=tmp; } for(i=1;i<=q;i++){ scanf("%d%d",&a,&b); tmp=t[a]; t[a]=t[b]; t[b]=tmp; }
重头戏在后面,明显是一道贪心,优先考虑1,然后是2,明显最外层的循环是:
for(int i=1;i<=n*m;i++)
当然,register加不加都可以的
然后就是空间上了,这题的空间开两个的数组是足够的,但是,建议使用一维数组,同时,如果需要三个这样的数组,可以把另一个不需要的数组拿来用,记得清空。
我的做法是先开一个数组来记录总每个数字的编码,位置编码如下:
1 | 2 | 3 | 4 |
---|---|---|---|
5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 |
用数组来表示第个数的位置,然后建立两个数组down和up,如果取了一个数,就在上面做标记。比如说当6号位被取之后,那么9号位、3号位、4号位就不能取了,其中,表示第列可行的区间即可。每次枚举的时候就可以判定,如果可以,就更新,如果不可以就直接跳过。
注意这道题目需要很多的细节。
#include<cstdio> #include<cmath> #include<iostream> #define maxn 5000*5000+39 using namespace std; int t[maxn],x[maxn]; int up[5039],down[5039]; int a,b,c,d,n,m,q; int main(){ scanf("%d%d%d%d%d",&x[0],&a,&b,&c,&d); scanf("%d%d%d",&n,&m,&q); int s=n*m; int i,j,tmp,tmps; for(i=1;i<=s+1;i++) x[i]=((long long)a*x[i-1]*x[i-1]+(long long)b*x[i-1]+c)%d; for(i=1;i<=s;i++) t[i]=i; for(i=1;i<=s;i++){ tmps=x[i]%i+1; tmp=t[i]; t[i]=t[tmps]; t[tmps]=tmp; } for(i=1;i<=q;i++){ scanf("%d%d",&a,&b); tmp=t[a]; t[a]=t[b]; t[b]=tmp; }//Insize t for(i=1;i<=s;i++) x[t[i]]=i; for(i=1;i<=m;i++) up[i]=0,down[i]=n+1;//Insize up and down int line,row; for(i=1;i<=s;i++){ line=ceil(1.0*x[i]/m); if(x[i]%m==0) row=m; else row=x[i]%m;//line 行 row 列 if(up[row]<line&&line<down[row]){ printf("%d ",i); for(j=1;j<=row-1;j++) down[j]=min(down[j],line+1); for(j=row+1;j<=m;j++) up[j]=max(line-1,up[j]); } } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具