Description

【NOI2014】随机数生成器_题解

Input

输入文件的第 1 行包含 5 个整数,依次为 x0, a, b, c, d,描述小 H 采用的随机数生成算法所需的随机种子。

第 2 行包含三个整数 N, M, Q,表示小 H 希望生成一个 1 到 N × M 的排列来填入她 N 行 M 列的棋盘,并且小 H 在初始的 N × M 次交换操作后,又进行了 Q 次额外的交换操作。

接下来 Q 行,第 i 行包含两个整数 ui, vi,表示第 i 次额外交换操作将交换 T_ui 和 T_vi 的值。

Output

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

Sample Input

【样例输入 1】

1 3 5 1 71

3 4 3

1 7

9 9

4 9

【样例输入 2】

654321 209 111 23 70000001

10 10 0

【样例输入 3】

123456 137 701 101 10000007

20 20 0

Sample Output

【样例输出 1】

1 2 6 8 9 12

【样例输出 2】

1 3 7 10 14 15 16 21 23 30 44 52 55 70 72 88 94 95 97

【样例输出 3】

1 10 12 14 16 26 32 38 44 46 61 81 84 101 126 128 135 140 152 156 201 206 237 242 243 253 259 269 278 279 291 298 338 345 347 352 354 383 395

Data Constraint

【NOI2014】随机数生成器_题解_02

思路

显然先要把随机排序弄好。

之前我犯了个错误,以为O(nm)标记会超时,结果全WA。
其实,因为真正搜到的是O((n+m-1)*nm),看起来TLE,实际上标记的数目不会太多。
so,放心模拟即可。

代码
#include<iostream>  
#include<cstdio>  
#include<cstring>  
using namespace std;  
const int N=5555;   
int n,m,ans[N*2],p[N*N],f[N][N];  
int a,b,c,d;  
void add(int x,int y)
{  
    for(int i=x+1;i<=n;i++)
    {  
        bool flag=true;  
        for(int j=y-1;j>=1;j--)  
        if(f[i][j])break;  
        else
        {  
            f[i][j]=1;  
            flag=false;  
        }  
        if(flag)break;  
    }  
    for(int i=x-1;i>=1;i--)
    {  
        bool flag=true;  
        for(int j=y+1;j<=m;j++)  
        if(f[i][j])break;  
        else
        {  
            f[i][j]=1;  
            flag=false;  
        }  
        if(flag)break;  
    }  
}
inline int F(long long x)
{  
    return (a*x*x+b*x+c)%d;  
}  
inline int x(int s)
{  
    return (s-1)/m+1;  
}  
inline int y(int s)
{  
    return (s-1)%m+1;  
}
int main()
{  
    int last,q,u,v;
    scanf("%d%d%d%d%d%d%d%d",&last,&a,&b,&c,&d,&n,&m,&q);  
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) f[i][j]=(i-1)*m+j;  
    for(int i=1;i<=n*m;i++)
    {  
        u=i;v=F(last)%i+1;  
        swap(f[x(u)][y(u)],f[x(v)][y(v)]);  
        last=F(last);  
    }  
    while(q--)
    {  
        scanf("%d%d",&u,&v);  
        swap(f[x(u)][y(u)],f[x(v)][y(v)]);  
    }  
    for(int i=1;i<=n*m;i++)p[f[x(i)][y(i)]]=i;  
    int cnt=0;  
    memset(f,0,sizeof(f));  
    for(int i=1;i<=n*m;i++)
    {  
        if(!f[x(p[i])][y(p[i])])
        {  
            ans[++cnt]=i;  
            add(x(p[i]),y(p[i]));  
            if(cnt==n+m-1)break;  
        }
    }
    for(int i=1;i<=cnt;i++) printf("%d ",ans[i]);  
    return 0;  
}