【bzoj3671】[Noi2014]随机数生成器 贪心

题目描述

输入

第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



题目大意

给定你一个用乱七八糟的方法生成的n*m的矩阵,矩阵中的元素是1~n*m的全排列,问从左上走到右下的路径中,把经过的元素从小到大排序后得到的字典序最小的路径是什么

题解

贪心

其实我真不知道出题人是怎么想的,题目描述搞得和数论似的,结果目的就是给出这个序列 = =

显然要考虑从小到大的n*m个数,如果能选就选,选了就更新其它不能选的位置。

如果一个点被选择,那么它的严格左下方和严格右上方的点都不能被选择,开一个标记数组记录它。

如果扫到一个点,它已经被标记过,那么它的左下(或右上)的点一定都被标记过。适当终止循环,时间复杂度是均摊$O(nm)$的。

但是本题卡内存差评,所以不能开数组记录每次的x,标记数组必须开成bool的等等。

另外本题需要使用桶排序,否则会TLE。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int val[25000010] , pos[25000010];
bool tag[5010][5010];
int main()
{
	int a , b , c , d , n , m , k , q , i , jx , jy , px , py , cnt = 0;
	long long x;
	scanf("%lld%d%d%d%d%d%d%d" , &x , &a , &b , &c , &d , &n , &m , &q) , k = n * m;
	for(i = 1 ; i <= k ; i ++ ) val[i] = i , x = (a * x * x + b * x + c) % d , pos[i] = (int)x;
	for(i = 1 ; i <= k ; i ++ ) swap(val[i] , val[pos[i] % i + 1]);
	while(q -- ) scanf("%d%d" , &px , &py) , swap(val[px] , val[py]);
	for(i = 1 ; i <= k ; i ++ ) pos[val[i]] = i;
	for(i = 1 ; i <= k ; i ++ )
	{
		px = (pos[i] - 1) / m + 1 , py = (pos[i] - 1) % m + 1;
		if(!tag[px][py])
		{
			printf("%d%c" , i , ++cnt == n + m - 1 ? ‘\n‘ : ‘ ‘);
			if(py > 1)
			{
				for(jx = px + 1 ; jx <= n ; jx ++ )
				{
					if(tag[jx][py - 1]) break;
					for(jy = py - 1 ; jy >= 1 ; jy -- )
					{
						if(tag[jx][jy]) break;
						tag[jx][jy] = 1;
					}
				}
			}
			if(py < m)
			{
				for(jx = px - 1 ; jx >= 1 ; jx -- )
				{
					if(tag[jx][py + 1]) break;
					for(jy = py + 1 ; jy <= m ; jy ++ )
					{
						if(tag[jx][jy]) break;
						tag[jx][jy] = 1;
					}
				}
			}
		}
	}
	return 0;
}
时间: 2024-08-05 11:17:34

【bzoj3671】[Noi2014]随机数生成器 贪心的相关文章

BZOJ3671 [Noi2014]随机数生成器 【贪心】

题目链接 BZOJ3671 题解 模拟题意生成矩阵贪心从小选择即可 每选择一个,就标记其左下右上矩阵 由于每次都是标记一个到边界的矩阵,所以一旦遇到标记过就直接退出即可,可以保证复杂度 还有就是空间和时间有点卡 #include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<map> #define R

BZOJ 3671 NOI2014 随机数生成器 贪心+暴力

题目大意:.....有点长自己看吧 首先既然是排序后的序列字典序最小,那么一定要选尽量小的数字走 然后T是1~m*n的序列 所以不存在重复(一开始我居然把这个条件看漏了) 好的这题贪心 每次选择没有被标记的最小点,然后把左下方和右上方都标记掉(记得标记重复时break,不然就挂了) 注意5000*5000的数组开两个int就是极限了 开多了妥妥MLE 所以T数组记得重复利用 暴力跑了38秒 不过这题每一行能够选择的区域一定是连续的 可以对于每一行维护一个l和r 每次更新取最值即可 这个代码跑了2

bzoj3671 [Noi2014]随机数生成器

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3671 [题解] 贪心从1...n*m取,开两个5000*5000的数组就够了,可以重复利用,坐标可以压到一个int里. 每次暴力标记不能访问的,标到已经有标记的就不用标了因为后面的肯定前面已经标记过了. 均摊复杂度就对了.复杂度$O(nm)$. 这破题还卡PE.. # include <stdio.h> # include <string.h> # include <i

【BZOJ3671】[Noi2014]随机数生成器 暴力

[BZOJ3535][Noi2014]随机数生成器 Description Input 第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 ) 的值.

NOI2014 随机数生成器.

3757. [NOI2014]随机数生成器 (Standard IO) Time Limits: 5000 ms  Memory Limits: 262144 KB Description Input 输入文件的第 1 行包含 5 个整数,依次为 x0, a, b, c, d,描述小 H 采用的随机数生成算法所需的随机种子. 第 2 行包含三个整数 N, M, Q,表示小 H 希望生成一个 1 到 N × M 的排列来填入她 N 行 M 列的棋盘,并且小 H 在初始的 N × M 次交换操作后,

【bzoj3671】[Noi2014]随机数生成器

优先按照它说明的方法处理数组 然后为了让数列中尽可能多的出现小的数字 所以1是必须要出现的,这样才能使整个数列的排序后字典序最小. 我们思考,如果2也能在这个数列中那就最好不过了 但是2有可能不在这个数列里,就是2在走了1就不可能走的地方的话,就不能走2了. 所以从小到大枚举数字,如果当前数字能走,就输出,然后标记所有走了这个节点就不能走的节点. #include<algorithm> #include<iostream> #include<cstdlib> #incl

BZOJ 3671 NOI 2014 随机数生成器 贪心

题目大意:实在是太难说明了,自己看pdf吧.. 思路:优先按照它说明的方法处理数组,然后为了让数列中尽可能多的出现小的数字,所以1是必须要出现的,这样才能使整个数列的排序后字典序最小.我们思考,如果2也能在这个数列中那就最好不过了,但是2有可能不在这个数列里,就是2在走了1就不可能走的地方的话,就不能走2了.所以从小到大枚举数字,如果当前数字能走,就输出,然后标记所有走了这个节点就不能走的节点.空间比较紧,5000*5000可以开int*2+bool*1,极限了.. CODE: #include

【BZOJ】【3671】【NOI2014】随机数生成器

贪心 嗯……其实生成这个矩阵就是一个$O(n^2)$的模拟 = = 然后?字典序最小?贪心呗= =能选1就选1,然后能选2就选2…… 我们发现,对于矩阵(1,1)~(n,m),假设1的位置是(x,y),那么我们选完1以后,可选的范围变成了:(1,1)~(x,y) & (x,y)~(n,m),也就是将一个矩阵拆成四块,我们可以在左上和右下两块中递归地进行选择…… 那么我们每次选完之后,新的可选的范围其实暴力O(n)维护就可以了,因为我们总共只选$O(n)$次,每次维护的复杂度是$O(n)$,总复杂

【矩阵乘】【NOI 2012】【cogs963】随机数生成器

963. [NOI2012] 随机数生成器 ★★ 输入文件:randoma.in 输出文件:randoma.out 简单对照 时间限制:1 s 内存限制:128 MB **[问题描写叙述] 栋栋近期迷上了随机算法,而随机数是生成随机算法的基础.栋栋准备使用线性同余法(Linear Congruential Method)来生成一个随机数列.这样的方法须要设置四个非负整数參数m,a,c,X[0],依照以下的公式生成出一系列随机数{Xn}: X[n+1]=(aX[n]+c) mod m 当中mod