ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[NOI2014]随机数生成器 题解

2021-02-15 21:01:05  阅读:258  来源: 互联网

标签:int 题解 d% 生成器 times NOI2014 算法 随机 交换


原题网址:
bzoj P3671
洛谷 P2354
附原题:

时间限制 内存限制
1.00s ~ 5.00s 250.00MB

题目描述

小 H 最近在研究随机算法。随机算法往往需要通过调用随机数生成函数(例如 Pascal 中的 random 和 C/C++中的 rand)来获得随机性。事实上,随机数生成函数也并不是真正的“随机”,其一般都是利用某个算法计算得来的。
比如,下面这个二次多项式递推算法就是一个常用算法:
算法选定非负整数\(x_0,a,b,c,d\)作为随机种子,并采用如下递推公式进行计算。
对于任意\(i \geq 1\) $x_i==(a×x+b×x_{i-1}^2+c) mod \(d\) 这样可以得到一个任意长度的非负整数数列 \({x_i,i\geq1}\),一般来说,我们认为这个数列是随机的。
利用随机序列\({xi},i\geq1\),我们还可以采用如下算法来产生一个\(1\)到 \(K\) 的随机排列\({T_i},i=1...k\)
1、初始设\(T\)为\(1\)到\(K\)的递增序列;
2、对\(T\)进行\(K\)次交换,第\(i\)次交换,交换\(T_i\)和\(T_{x_i}\)mod \(_{i+1}\)
此外,小 H 在这\(K\)次交换的基础上,又额外进行了\(Q\)次交换操作,对于第i 次额外交换,小 H 会选定两个下标\(u_i和v_i\),并交换\(T_{v_i}和T_{v_i}\)的值
为了检验这个随机排列生成算法的实用性,小 H 设计了如下问题:
小 H 有一个 N 行 M 列的棋盘,她首先按照上述过程,通过\(N \times M + Q\)次交换操作,生成了一个\(1\sim N \times M∼N\times M\)的随机排列,\(T_i,i=1...N \times M\)。然后将这\(N \times M\)个数逐行逐列依次填入这个棋盘:也就是第\(i\)行第\(j\)列的格子上所填入的数应为\(T_{(i-1)\times M+u_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 \times M\) 的排列来填入她\(N\)行\(M\)列的棋盘,并且小H在初始的\(N \times 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

数据范围

在这里插入图片描述

题解内容

终于把题目写完了,markdown写了半个多小时
前面blablabla讲了一大堆废话
一句话讲,就是教你怎么生成一个随机函数,代码直接按照它的做法写下来,注意数据范围,要加\(long long\)不然会直接RE就像我一样:
在这里插入图片描述
炸\(int\)了,所以加上\(long long\)强制转换,就可以了~~~~~~

    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加不加都可以的
然后就是空间上了,这题的空间开两个\(5000\times5000\)的数组是足够的,但是,建议使用一维数组,同时,如果需要三个这样的数组,可以把另一个不需要的数组拿来用,记得清空。

我的做法是先开一个数组来记录总每个数字的编码,位置编码如下:

1 2 3 4
5 6 7 8
9 10 11 12

用数组\(x_i\)来表示第\(i\)个数的位置,然后建立两个数组down和up,如果取了一个数,就在上面做标记。比如说当6号位被取之后,那么9号位、3号位、4号位就不能取了,其中,\(up_i,down_i\)表示第\(i\)列可行的区间即可。每次枚举的时候就可以判定,如果可以,就更新,如果不可以就直接跳过。
这道题目需要很多的细节,所以,经过反复调试,终于,推出了AC代码

#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;
}

标签:int,题解,d%,生成器,times,NOI2014,算法,随机,交换
来源: https://www.cnblogs.com/jiangtaizhe001/p/14404445.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有