zoukankan      html  css  js  c++  java
  • BZOJ_3671_[Noi2014]随机数生成器_set+贪心

    BZOJ_3671_[Noi2014]随机数生成器_set

    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≤108

    0≤x0<d≤1081≤ui,vi≤N×M


    先把矩阵按照题意搞出来。

    然后考虑贪心的从1到n*m开始枚举,能选则选。

    可以发现合法的点集满足横坐标递增的同时纵坐标也递增,考虑用set维护这样的一个点集。

    然后我就用$O(n^2logn)$的复杂度水过了这道题。

    ps.卡空间,需要把横纵坐标压成一个int。

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <set>
    using namespace std;
    #define N 25000500
    typedef long long ll;
    int P[N],A[N],n,m,Q,a,b,c,d;
    struct Point {
        int x,y;
        bool operator < (const Point &p) const {
            return x==p.x?y<p.y:x<p.x;
        }
    };
    set<Point>S;
    bool check(int x,int y) {
        set<Point>::iterator it=S.lower_bound((Point){x,y});
        if(it==S.begin()&&it==S.end()) return 1;
        if(it==S.begin()) {
            return (*it).y>=y;
        }
        if(it==S.end()) {
            it--;
            return (*it).y<=y;
        }
        return (*it).y>=y&&(*(--it)).y<=y;
    }
    int main() {
        scanf("%d%d%d%d%d%d%d%d",&P[0],&a,&b,&c,&d,&n,&m,&Q);
        register int i,lim=n*m;
        for(i=1;i<=lim;i++) P[i]=(ll(a)*P[i-1]*P[i-1]+ll(b)*P[i-1]+c)%d,A[i]=i;
        for(i=1;i<=lim;i++) swap(A[i],A[P[i]%i+1]);
        int x,y;
        while(Q--) {
            scanf("%d%d",&x,&y); swap(A[x],A[y]);
        }
        int cnt=0;
        for(i=1;i<=lim;i++) P[A[i]]=i;
        for(i=1;i<=lim;i++) {
            x=P[i]%m; if(!x) x=m;
            y=P[i]/m+(x!=m);
            if(check(x,y)) {
                printf("%d",i); cnt++;
                if(cnt==n+m-1) {puts("");return 0;}
                else printf(" ");
                S.insert((Point){x,y});
            }
        }
    }
    
  • 相关阅读:
    二元函数求一定区间上的最大值问题
    LOF异常检测算法实现
    失效项目总代码汇总
    layui弹出层layer.open 中的content问题
    分治算法基本原理和实践
    Android 文件存储浅析
    详解 CmProcess 跨进程通信的实现
    View Animation 运行原理解析
    margin-top失效及解决办法
    vue自定义移动端touch事件之点击、滑动、长按事件
  • 原文地址:https://www.cnblogs.com/suika/p/9426940.html
Copyright © 2011-2022 走看看