3671: [Noi2014]随机数生成器
Time Limit: 50 Sec Memory Limit: 256 MBSubmit: 1593 Solved: 704
[ Submit][ Status][ Discuss]
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 ) 的值。
Output
输出一行,包含 N+M-1 个由空格隔开的正整数,表示可以得到的字典序最小的路径序列。
Sample Input
3 4 3
1 7
9 9
4 9
Sample Output
HINT
本题的空间限制是 256 MB,请务必保证提交的代码运行时所使用的总内存空间不超过此限制。
一个32位整数(例如C/C++中的int和Pascal中的Longint)为4字节,因而如果在程序中声明一个长度为 1024×1024 的32位整型变量的数组,将会占用 4 MB 的内存空间。
2≤N,M≤5000
0≤Q≤50000
0≤a≤300
0≤b,c≤108
0≤x0<d≤1081≤ui,vi≤N×M
Source
首先,生成出题目要的那个N*M排列
因为目标是字典序最小的路径序列,所以贪心地想,越小的数字就更需要存在里面了
首先让1进去,然后检查2是否合法,合法就放入否则考虑下一个。。。。。。
因为路径只能向右下方,所以可以产生一些限制
考虑到达每个点所需要的步数是唯一确定的,这就意味着每个点唯一对应路径上的一个位置
每次加入一个点,找到它在路径序列中的位置,找到它的前驱,后继
那么,它和前驱、后继就形成了两个小的矩形,它们之间的点只能在小矩形内产生
所以如果一个点合法,那么O(n)把其它位置的合法区间暴力更新一下就行了
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<bitset>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
const int N = 5005;
typedef long long LL;
int n,m,q,tot,A[N*N],pos[N*N],u[2*N],l[2*N],d[2*N],r[2*N],Ans[2*N];
LL seed,a,b,c,p;
bool cmp(const int &a,const int &b) {return A[a] < A[b];}
int Calc() {return seed = (a * seed % p * seed + b * seed + c) % p;}
int getint()
{
char ch = getchar(); int ret = 0;
while (ch < '0' || '9' < ch) ch = getchar();
while ('0' <= ch && ch <= '9')
ret = ret * 10 + ch - '0',ch = getchar();
return ret;
}
void Work(int &x,int &y,int &k,int g)
{
y = g % m; x = g / m;
k = x + y; ++x; ++y;
}
void Modify(int x,int y,int k)
{
for (int i = k - 1; i >= 0; i--)
{
if (Ans[i]) break;
d[i] = x; r[i] = y;
}
for (int i = k + 1; k <= n + m - 1; i++)
{
if (Ans[i]) break;
u[i] = x; l[i] = y;
}
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
seed = getint(); a = getint(); b = getint(); c = getint();
p = getint(); n = getint(); m = getint(); q = getint();
for (int i = 1; i <= n * m; i++)
A[i] = i,swap(A[i],A[Calc() % i + 1]);
while (q--)
{
int x = getint(),y = getint();
swap(A[x],A[y]);
}
for (int i = 1; i <= n * m; i++) pos[A[i]] = i;
for (int i = 1; i <= n + m - 1; i++)
u[i] = 1,d[i] = n,l[i] = 1,r[i] = m;
for (int i = 1; i <= n * m; i++)
{
int x,y,k; Work(x,y,k,pos[i] - 1); if (Ans[k]) continue;
if (x < u[k] || d[k] < x || y < l[k] || r[k] < y) continue;
Ans[k] = pos[i]; Modify(x,y,k); ++tot;
if (tot == n + m - 1) break;
}
sort(Ans,Ans + tot,cmp);
for (int i = 0; i < tot - 1; i++) printf("%d ",A[Ans[i]]);
cout << A[Ans[tot - 1]] << endl;
//cerr << (double)(clock()) / CLOCKS_PER_SEC << endl;
return 0;
}