[NOI2014]随机数生成器

题意

  给定一个初始随机种子和一个随机数生成器,同时给出若干个交换对,求出交换后的矩阵路径序列排序后字典序最小的合法路径

题解

  一开始的处理很简单,直接按照题目的要求进行模拟,然后将矩阵生成即可,关键是后面的寻找路径过程
  容易想到,1肯定是要被选进去的,因为是要求将路径序列排序后的字典序最小;然后贪心地从小到大选择,判断是否能够加入当前序列,知道序列长度达到要求停止
  现在的问题就是怎么判断决策点能否加入当前序列。考虑对于每一行维护合法的区间(初始为[1,m]),设决策点为(xy),如果l[x]<=y<=r[x],那么当前点就可以加入到序列中,然后就要更新矩阵的合法区间
  对于i[xpre,x]xpre为决策点之前那一个点的横坐标),只需将r[i]更新为y即可,对于i[x,xnext],只需将l[i]更新为y即可

复杂度

O(跑得过)

代码

#include<iostream>
#include<cstdlib>
#include<cstdio>
#define Rint register int
#define Lint long long int
using namespace std;
const int N=5010;
int l[N],r[N],T[N*N],Tn[N*N];
int n,m,q;
Lint a,b,c,d,x_0;
int main()
{
    int u,v,x;
    scanf("%lld%lld%lld%lld%lld",&x_0,&a,&b,&c,&d);
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=n*m;i++)   T[i]=i;
    for(int i=1;i<=n*m;i++)
    {
        x=(a*x_0*x_0+b*x_0+c)%d;
        swap( T[i],T[x%i+1] );
        x_0=x;
    }
    for(int i=1;i<=q;i++)
    {
        scanf("%d%d",&u,&v);
        swap( T[u],T[v] );
    }
    for(int i=1;i<=n;i++)   for(int j=1;j<=m;j++)   x=T[(i-1)*m+j],Tn[x]=(i-1)*m+j;
    for(int i=1;i<=n;i++)   l[i]=1,r[i]=m;
    for(int i=1;i<=n*m;i++)
    {
        u=Tn[i]%m ? Tn[i]/m+1:Tn[i]/m,v=Tn[i]%m ? Tn[i]%m:m;
        if( v<l[u] || v>r[u] )   continue ;
        for(int x=u-1;x>=1;x--)
            if( v<r[x] )   r[x]=v;
            else   break ;
        for(int x=u+1;x<=n;x++)
            if( v>l[x] )   l[x]=v;
            else   break ;
        printf("%d ",i);
    }
    printf("\n");
    return 0;
}
posted @ 2018-02-19 22:05  清疚  阅读(106)  评论(0)    收藏  举报