题意
给定一个初始随机种子和一个随机数生成器,同时给出若干个交换对,求出交换后的矩阵路径序列排序后字典序最小的合法路径
题解
一开始的处理很简单,直接按照题目的要求进行模拟,然后将矩阵生成即可,关键是后面的寻找路径过程
容易想到,1肯定是要被选进去的,因为是要求将路径序列排序后的字典序最小;然后贪心地从小到大选择,判断是否能够加入当前序列,知道序列长度达到要求停止
现在的问题就是怎么判断决策点能否加入当前序列。考虑对于每一行维护合法的区间(初始为 [1,m] [ 1 , m ] ),设决策点为 (x,y) ( x , y ) ,如果 l[x]<=y<=r[x] l [ x ] <= y <= r [ x ] ,那么当前点就可以加入到序列中,然后就要更新矩阵的合法区间
对于 i∈[xpre,x] i ∈ [ x p r e , x ] ( xpre x p r e 为决策点之前那一个点的横坐标),只需将 r[i] r [ i ] 更新为 y y 即可,对于,只需将 l[i] l [ i ] 更新为 y y <script type="math/tex" id="MathJax-Element-12">y</script>即可
复杂度
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;
}