[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 ...
随机推荐
- js遍历json数据
先看看json返回的数据结构: 我需要遍历取出bookreno 与 title 加载到页面容器中去 首先我要取到 recommendedBookList 字典结构数据,然后遍历反射到相应对象 ...
- asp.net网站安全常见问题与防范
1:SQL 注入 2:XSS 3:CSRF 4:文件上传 1:SQL 注入 引起原因: 其实现在很多网站中都存在这种问题.就是程序中直接进行SQL语句拼接.可能有些读者不太明白. 下面通过一个登录时对 ...
- 团队项目作业第二项:利用NABCD模型进行竞争性需求分析
项目需求分析与建议--NABCD模型(王鲁跃负责) N (Need 需求) 对于现在的学生来说,我们认为打字是很重要的.不管在什么方面都需要进行电脑打字,例如文员.QQ.MSN.制作,论文等等,都需要 ...
- 使用Git进行代码管理心得
关于使用Git for Windows来clone和上传项目 首先到Git for Windows的官网下载并安装 在本地用来保存clone文件的文件夹右键,选择Git Bash Here: 在打开的 ...
- ZOJ 3201 树形dp+背包(简单题)
#include<cstdio> #include<vector> #include<cstring> #include<iostream> using ...
- 模拟Modbus协议问题
问题: 在嵌入式系统开发中,Modbus协议是工业控制系统中广泛应用的一种协议.本题用来简单模拟Modbus协议,只需根据条件生成符合该协议的数据帧,并解析所获取的数据.假设设备使用的协议发送数据格式 ...
- 利用symbolsource/gitlink调试你的nuget包
关键字: 如何调试Nuget下载的dll? VS github 调试 参考文章: http://docs.nuget.org/create/creating-and-publishing-a-sy ...
- 安卓系统源码编译系列(六)——单独编译内置浏览器WebView教程
原文 http://blog.csdn.net/zhaoxy_thu/article/details/18883015 本文主要对从 ...
- Android学习笔记01-Mac下搭建Java开发环境
一 安装JDK 下载 mac 下专用的jdk1.7, 下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downlo ...
- Eclipse开发Android程序如何在手机上运行
android开发不论是在真机上调试还是最终发布到真机上都非常简单,过程如下: 1.安装usb驱动 手机要能与电脑相连,当然要安驱动了.效果就是你插入手机,电脑显示驱动已识别.驱动安装的官方教程:ht ...