zoukankan      html  css  js  c++  java
  • [luogu] P2354 [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 ) 的值。

    Output

    输出一行,包含 N+M-1 个由空格隔开的正整数,表示可以得到的字典序最小的路径序列。

    Sample Input

    1 3 5 1 71
    3 4 3
    1 7
    9 9
    4 9

    Sample Output

    1 2 6 8 9 12

    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≤10^8)

    (0≤x_0<d≤10^8,1≤ui,vi≤N×M)

    题解

    这个题目。。
    和随机没有一点关系。。和图的建立没有一点关系。
    你照着题目描述(O(nm))是可以暴力搞出图来的。
    问题是怎么去求出路径。
    我最开始的想法是从(1)(n*m),一个一个暴力求,记录此时最优情况下的最左上角和最右下角。因为有拐弯的情况。拐弯即使样例中1-6-2.
    但是这样很显然是错的,还是要记录每一个数的情况,但是这样加入一个数以后再一个一个往之前匹配,时间复杂度会变为(O(n^3))
    我们可以换个思路记录一下,对于一个数,取了它以后,它所在位置的右上和左下肯定是取不了了。我们就用数组记录一下。
    把矩阵转化为行。对于行定义一个上下界,然后每次放入一个数判断加更新即可。因为只有一行,且更新次数不超过(O(n+m-1))次,所以时间复杂度还是(O(n*m)),就是常数奇大无比。

    Code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    using namespace std;
    const int N=5001;
    int t[N*N],f[N*N],up[N],down[N];
    long long a,b,c,d;
    int n,m,q;
    int read(){
    	int x=0,w=1;char ch=getchar();
    	while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    	return x*w;
    }
    
    int main(){
    	f[0]=read();a=read();b=read();c=read();d=read();
    	n=read();m=read();q=read();
    	for(int i=1;i<=n*m;i++){
    		f[i]=(a*f[i-1]*f[i-1]+b*f[i-1]+c)%d;
    	}
    	for(int i=1;i<=n*m;i++)t[i]=i;
    	for(int i=1;i<=n*m;i++){
    		swap(t[i],t[f[i]%i+1]);
    	}
    	for(int i=1;i<=q;i++){
    		int x=read(),y=read();
    		swap(t[x],t[y]);
    	}
    	for(int i=1;i<=n*m;i++)f[t[i]]=i;
    	for(int i=1;i<=m;i++)up[i]=1,down[i]=n;
    	for(int i=1;i<=n*m;i++){
    		int x=f[i]%m==0?m:f[i]%m,y=(f[i]-1)/m+1;
    		if(up[x]<=y&&down[x]>=y){
    			printf("%d ",i);
    			for(int j=x+1;j<=m;j++)up[j]=max(up[j],y);
    			for(int j=1;j<x;j++)   down[j]=min(down[j],y);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    多线程与MySQL(十)
    多进程与多线程(九)
    异常处理与网络编程(八)
    面向对象,绑定方法与异常处理(七)
    模块与对象(六)
    包与模块(五)
    迭代器与函数Python学习(四)
    函数与装饰器Python学习(三)
    数据库
    并发编程
  • 原文地址:https://www.cnblogs.com/hhh1109/p/10667111.html
Copyright © 2011-2022 走看看