[BZOJ3671][UOJ#6][NOI2014]随机数生成器
[BZOJ3671][UOJ#6][NOI2014]随机数生成器
试题描述
小H最近在研究随机算法。随机算法往往需要通过调用随机数生成函数(例如Pascal中的random和C/C++中的rand)来获得随机性。事实上,随机数生成函数也并不是真正的“随机”,其一般都是利用某个算法计算得来的。
比如,下面这个二次多项式递推算法就是一个常用算法:
算法选定非负整数x0,a,b,c,d作为随机种子,并采用如下递推公式进行计算。
对于任意i≥1,xi=(ax2i−1+bxi−1+c)mod d 。
这样可以得到一个任意长度的非负整数数列{xi}i≥1,一般来说,我们认为这个数列是随机的。
利用随机序列{xi}i≥1,我们还可以采用如下算法来产生一个1到K的随机排列{Ti}i=1~K :
- 初始设T为1到K的递增序列;
- 对T进行K次交换,第i次交换,交换Ti和T(ximodi)+1的值。
此外,小H在这K次交换的基础上,又额外进行了Q次交换操作,对于第i次额外交换,小H会选定两个下标ui和vi,并交换Tui和Tvi的值。
为了检验这个随机排列生成算法的实用性,小H设计了如下问题:
小H有一个N行M列的棋盘,她首先按照上述过程,通过N×M+Q次交换操作,生成了一个 1∼N×M的随机排列{Ti}N×Mi=1然后将这N×M个数逐行逐列依次填入这个棋盘:也就是第 i行第 j列的格子上所填入的数应为T(i−1)×M+j。
接着小H希望从棋盘的左上角,也就是第一行第一列的格子出发,每次向右走或者向下走,在不走出棋盘的前提下,走到棋盘的右下角,也就是第N行第M列的格子。
小H把所经过格子上的数字都记录了下来,并从小到大排序,这样,对于任何一条合法的移动路径,小H都可以得到一个长度为N+M−1的升序序列,我们称之为路径序列。
小H想知道,她可能得到的字典序最小的路径序列应该是怎样的呢?
输入
输入文件的第1行包含5个整数,依次为x0,a,b,c,d,描述小H采用的随机数生成算法所需的随机种子。
第2行包含三个整数 N,M,Q,表示小H希望生成一个11 到N×M的排列来填入她N行M列的棋盘,并且小H在初始的N×M次交换操作后,又进行了Q次额外的交换操作。
接下来Q行,第i行包含两个整数ui,vi,表示第i次额外交换操作将交换 Tui和Tvi的值
输出
输出一行,包含 N+M−1个由空格隔开的正整数,表示可以得到的字典序最小的路径序列。
输入示例1
输出示例1
输入示例2
输出示例2
输入示例3
输出示例3
输入示例4
传送门(点击下载)
输出示例4
数据规模及约定
2≤N,M≤5000
0≤Q≤50000
0≤a≤300
0≤b,c≤108
0≤x0<d≤108
1≤ui,vi≤N×M
题解
既然要求排完序之后的字典序最小,那显然可以用贪心来解决。
先把起点和终点的数加进来,之后从1到n·m依次判断。判断数i时先找到i左边最靠近i的一列(称为列L),再找到右边最靠近i的一列(称为列R),以列L中已插入的最靠下的位置和列R中已插入的最靠上的位置分别作为矩形的左上、右下顶点,若i在这个矩形内部则可以取到,否则不能取到。对于每一个可以去到的i,将其行、列的位置加进来。
这个好像可以用线段树搞?
仔细看题,加入操作不超过9999次(n + m - 1次),所以暴!力!即!可!【用线段树反而会多一个log】
下面这个代码是97分的,感谢UOJ用户 r_64 的hack,帮我找到了代码的Bug。(读者不妨看看我错在哪里)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std; const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *tail;
inline char Getchar() {
if(Head == tail) {
int l = fread(buffer, 1, BufferSize, stdin);
tail = (Head = buffer) + l;
}
return *Head++;
}
int read() {
int x = 0, f = 1; char c = Getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
return x * f;
} #define maxn 5010
#define maxm 25000010
#define LL long long
int n, m, q, x[maxm], T[maxm], tl[maxn], tr[maxn], high[maxn], low[maxn]; int ans[maxn<<1], cnt;
short idy[maxm];
int main() {
x[0] = read(); int a = read(), b = read(), c = read(), d = read();
n = read(); m = read(); q = read();
for(int i = 1; i <= n * m; i++) {
x[i] = (((LL)a * x[i-1] * x[i-1]) % d + ((LL)b * x[i-1]) % d + c) % d;
T[i] = i;
}
for(int i = 1; i <= n * m; i++) swap(T[i], T[x[i]%i+1]);
while(q--) {
int x = read(), y = read();
if(x != y) swap(T[x], T[y]);
}
for(int i = 1; i <= n * m; i++)
x[T[i]] = (i-1) / m + 1, idy[T[i]] = (i-1) % m + 1; for(int i = 2; i < m; i++) tl[i] = 1, tr[i] = m, high[i] = n+1, low[i] = 0;
high[1] = low[1] = 1; high[m] = low[m] = n;
for(int i = 1; i <= n * m; i++) if(i != T[1] && i != T[n*m]) {
int X = x[i], y = idy[i];
if((y == 1 || low[tl[y]] <= X) && (y == m || X <= high[tr[y]])) {
ans[++cnt] = i;
for(int j = tl[y]; j < y; j++) tr[j] = y;
for(int j = y+1; j <= tr[y]; j++) tl[j] = y;
// printf("%d %d %d\n", i, x, y);
// for(int j = 1; j <= m; j++) printf("%d ", tl[j]); putchar('\n');
// for(int j = 1; j <= m; j++) printf("%d ", tr[j]); putchar('\n');
low[y] = max(low[y], X); high[y] = min(high[y], X);
}
}
else ans[++cnt] = i; for(int i = 1; i < cnt; i++) printf("%d ", ans[i]); printf("%d\n", ans[cnt]); return 0;
}
100分:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std; const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *tail;
inline char Getchar() {
if(Head == tail) {
int l = fread(buffer, 1, BufferSize, stdin);
tail = (Head = buffer) + l;
}
return *Head++;
}
int read() {
int x = 0, f = 1; char c = Getchar();
while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
return x * f;
} #define maxn 5010
#define maxm 25000010
#define LL long long
int n, m, q, x[maxm], T[maxm], tl[maxn], tr[maxn], high[maxn], low[maxn]; int ans[maxn<<1], cnt;
short idy[maxm];
int main() {
x[0] = read(); int a = read(), b = read(), c = read(), d = read();
n = read(); m = read(); q = read();
for(int i = 1; i <= n * m; i++) {
x[i] = (((LL)a * x[i-1] * x[i-1]) % d + ((LL)b * x[i-1]) % d + c) % d;
T[i] = i;
}
for(int i = 1; i <= n * m; i++) swap(T[i], T[x[i]%i+1]);
while(q--) {
int x = read(), y = read();
if(x != y) swap(T[x], T[y]);
}
for(int i = 1; i <= n * m; i++)
x[T[i]] = (i-1) / m + 1, idy[T[i]] = (i-1) % m + 1; for(int i = 1; i <= m; i++) tl[i] = 1, tr[i] = m, high[i] = n+1, low[i] = 0;
high[1] = low[1] = 1; high[m] = low[m] = n;
for(int i = 1; i <= n * m; i++) if(i != T[1] && i != T[n*m]) {
int X = x[i], y = idy[i];
if((y == 1 || low[tl[y]] <= X) && (y == m || X <= high[tr[y]])) {
ans[++cnt] = i;
for(int j = tl[y]; j < y; j++) tr[j] = y;
for(int j = y+1; j <= tr[y]; j++) tl[j] = y;
// printf("%d %d %d\n", i, x, y);
// for(int j = 1; j <= m; j++) printf("%d ", tl[j]); putchar('\n');
// for(int j = 1; j <= m; j++) printf("%d ", tr[j]); putchar('\n');
low[y] = max(low[y], X); high[y] = min(high[y], X);
}
}
else ans[++cnt] = i; for(int i = 1; i < cnt; i++) printf("%d ", ans[i]); printf("%d\n", ans[cnt]); return 0;
}
[BZOJ3671][UOJ#6][NOI2014]随机数生成器的更多相关文章
- 【BZOJ3671】[Noi2014]随机数生成器 暴力
[BZOJ3535][Noi2014]随机数生成器 Description Input 第1行包含5个整数,依次为 x_0,a,b,c,d ,描述小H采用的随机数生成算法所需的随机种子.第2行包含三个 ...
- BZOJ_3671_[Noi2014]随机数生成器_set+贪心
BZOJ_3671_[Noi2014]随机数生成器_set Description Input 第1行包含5个整数,依次为 x_0,a,b,c,d ,描述小H采用的随机数生成算法所需的随机种子.第 ...
- NOI2014 随机数生成器
随机数生成器 [问题描述] 小H最近在研究随机算法.随机算法往往需要通过调用随机数生成函数(例如Pascal中的random和C/C++中的rand)来获得随机性.事实上,随机数生成函数也并不是真正的 ...
- luogu P2354 [NOI2014]随机数生成器 贪心 卡空间 暴力
LINK:随机数生成器 观察数据范围还是可以把矩阵给生成出来的. 考虑如何求出答案.题目要求把选出的数字从小到大排序后字典序尽可能的小 实际上这个类似于Mex的问题. 所以要从大到小选数字 考虑选择一 ...
- BZOJ3671 [Noi2014]随机数生成器 【贪心】
题目链接 BZOJ3671 题解 模拟题意生成矩阵贪心从小选择即可 每选择一个,就标记其左下右上矩阵 由于每次都是标记一个到边界的矩阵,所以一旦遇到标记过就直接退出即可,可以保证复杂度 还有就是空间和 ...
- BZOJ3671/UOJ6 [Noi2014]随机数生成器
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- bzoj3671 [Noi2014]随机数生成器
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3671 [题解] 贪心从1...n*m取,开两个5000*5000的数组就够了,可以重复利用, ...
- BZOJ3671: [Noi2014]随机数生成器(贪心)
Time Limit: 50 Sec Memory Limit: 256 MBSubmit: 2098 Solved: 946[Submit][Status][Discuss] Descripti ...
- 【bzoj3671】[Noi2014]随机数生成器 贪心
题目描述 输入 第1行包含5个整数,依次为 x_0,a,b,c,d ,描述小H采用的随机数生成算法所需的随机种子.第2行包含三个整数 N,M,Q ,表示小H希望生成一个1到 N×M 的排列来填入她 N ...
随机推荐
- 重构笔记---MEF框架(下)
概述 上一篇介绍了MEF的一个很简单很基本的应用,实现了MEF框架并展示了MEF框架的一些基本的要求和设置,这些基础知识很重要,接下来我们分析一下如何扩展或增强MEF框架内容. 增强的Contract ...
- 重构笔记---MEF框架(上)
概述 这篇文章的目的是简要分析对比MAF和MEF,并详细举出MEF设计中的细节和扩展上的细节,达到让读者能实际操作的目的.其中,MAF的设计会附上我的代码,其实就是官方的代码我自己手动联系了一遍,但还 ...
- java和linux的编码
最近要使用中科院计算所的关键词工具NLPIR,用java调用,在windows下测试后放到linux下跑,就发现会有乱码. windows下默认是GBK,linux下是utf-8,因此在意料之中(尽管 ...
- 教你一步一步实现一个Promise
Promise我想现在大家都非常熟悉了,主要作用就是解决异步回调问题,这里简单介绍下. Promise规范是CommonJS规范之一,而Promise规范又分了好多种,比如 Promises/A.Pr ...
- nodeJs抓取网页
var fs = require('fs'); var jquery = require('jquery'); var url = require('url'); var data = { 0 : ' ...
- java 关键字 transient
一个对象实现了Serilizable 接口,该对象就可以被序列化. 然而在实际开发工程中,我们会遇到,这个类的有些属性不需要序列化,比如包含用户的敏感信息(如密码),为了安全起见,不希望在网络操作(主 ...
- Java-EnumSet
如下 package 集合类.Set类; /** * Set不允许重复数据 */ /** * 这个类是1.5开始有的, * 目前个人使用量几乎为零,很少使用 * 其使用方式和普通的Set没有区别,只是 ...
- ajax入门详解
l 一个实例 在开始正式讲解 Ajax之前,首先让我们先来看看Google Map使用Ajax改善其产品设计的效果. 1. 在浏览器地址栏中输入http://maps.google.com打开Goog ...
- redis安装步骤
7.1创建业务安装用户 安装和配置Redis软件时,需要使用redis用户登录服务器进行相关操作,因此需要创建redis的业务安装用户组和redis的业务安装用户.此操作在主备机上同时进行. 创建用户 ...
- Fedora 20下配置samba服务器
1 安装samba [root@localhost ~]# yum –y install samba ← 通过网络安装samba yum -y install samba-client // ...